diff --git a/Config.in b/Config.in index 30d7eca4a..b04c65a71 100644 --- a/Config.in +++ b/Config.in @@ -206,13 +206,6 @@ config DEBUG help Adds -g3 to the CFLAGS -config DEBUG_DIR - bool "Install debugging binaries into a staging directory" - default n - help - This will install all compiled package binaries into build_dir/target-*/debug-*/, - useful for cross-debugging via gdb/gdbserver - config IPV6 bool prompt "Enable IPv6 support in packages" diff --git a/include/autotools.mk b/include/autotools.mk index cd333577c..e1535d0b1 100644 --- a/include/autotools.mk +++ b/include/autotools.mk @@ -1,5 +1,5 @@ # -# Copyright (C) 2007-2009 OpenWrt.org +# Copyright (C) 2007-2010 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -13,10 +13,24 @@ define replace endef +PKG_LIBTOOL_PATHS?=$(CONFIGURE_PATH) + # replace copies of ltmain.sh with the build system's version -update_libtool_common=$(call replace,ltmain.sh,$(STAGING_DIR)/host/share/libtool,$(CONFIGURE_PATH)/)$(call replace,libtool.m4,$(STAGING_DIR)/host/share/aclocal,$(CONFIGURE_PATH)/) -update_libtool=$(call replace,libtool,$(STAGING_DIR)/host/bin,$(CONFIGURE_PATH)/)$(call update_libtool_common) -update_libtool_ucxx=$(call replace,libtool,$(STAGING_DIR)/host/bin,$(CONFIGURE_PATH)/,libtool-ucxx)$(call update_libtool_common) +update_libtool_common = \ + $(foreach p,$(LIBTOOL_PATHS), \ + $(call replace,ltmain.sh,$(STAGING_DIR)/host/share/libtool,$(p)/) \ + $(call replace,libtool.m4,$(STAGING_DIR)/host/share/aclocal,$(p)/) \ + ) +update_libtool = \ + $(foreach p,$(PKG_LIBTOOL_PATHS), \ + $(call replace,libtool,$(STAGING_DIR)/host/bin,$(p)/) \ + ) \ + $(call update_libtool_common) +update_libtool_ucxx = \ + $(foreach p,$(PKG_LIBTOOL_PATHS), \ + $(call replace,libtool,$(STAGING_DIR)/host/bin,$(p)/,libtool-ucxx) \ + ) \ + $(call update_libtool_common) # prevent libtool from linking against host development libraries @@ -24,15 +38,12 @@ define libtool_fixup_libdir find $(1) -name '*.la' | $(XARGS) \ $(SED) "s,\(^libdir='\| \|-L\|^dependency_libs='\)/usr/lib,\1$(STAGING_DIR)/usr/lib,g" \ -e "s,$(STAGING_DIR)/usr/lib/\(libstdc++\|libsupc++\).la,$(TOOLCHAIN_DIR)/usr/lib/\1.la,g" - find $(2) -name '*.la' | $(XARGS) \ - $(SED) "s,\(^libdir='\| \|-L\|^dependency_libs='\)/usr/lib,\1$(STAGING_DIR)/usr/lib,g" \ - -e "s,$(STAGING_DIR)/usr/lib/\(libstdc++\|libsupc++\).la,$(TOOLCHAIN_DIR)/usr/lib/\1.la,g" endef define remove_version_check if [ -f "$(PKG_BUILD_DIR)/$(CONFIGURE_PATH)/configure" ]; then \ $(SED) \ - 's,pardus_ltmain_version=.*,pardus_ltmain_version="$$$$pardus_lt_version",' \ + 's,\(gentoo\|pardus\)_ltmain_version=.*,\1_ltmain_version="$$$$\1_lt_version",' \ $(PKG_BUILD_DIR)/$(CONFIGURE_PATH)/configure; \ fi endef diff --git a/include/download.mk b/include/download.mk index a50a5e936..e19cd4147 100644 --- a/include/download.mk +++ b/include/download.mk @@ -1,5 +1,5 @@ -# -# Copyright (C) 2007 OpenWrt.org +# +# Copyright (C) 2006-2010 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -8,7 +8,7 @@ DOWNLOAD_RDEP=$(STAMP_PREPARED) $(HOST_STAMP_PREPARED) # Try to guess the download method from the URL -define dl_method +define dl_method $(strip \ $(if $(2),$(2), \ $(if $(filter @GNOME/% @GNU/% @KERNEL/% @SF/% ftp://% http://% file://%,$(1)),default, \ @@ -16,9 +16,9 @@ $(strip \ $(if $(filter svn://%,$(1)),svn, \ $(if $(filter cvs://%,$(1)),cvs, \ $(if $(filter hg://%,$(1)),hg, \ - unknown \ - ) \ - ) \ + unknown \ + ) \ + ) \ ) \ ) \ ) \ @@ -26,7 +26,7 @@ $(strip \ ) endef -# code for creating tarballs from cvs/svn/git/hg checkouts - useful for mirror support +# code for creating tarballs from cvs/svn/git/bzr/hg checkouts - useful for mirror support dl_pack/bz2=$(TAR) cfj $(1) $(2) dl_pack/gz=$(TAR) cfz $(1) $(2) dl_pack/unknown=echo "ERROR: Unknown pack format for file $(1)"; false @@ -49,19 +49,18 @@ endef define DownloadMethod/cvs $(call wrap_mirror, \ echo "Checking out files from the cvs repository..."; \ - mkdir -p $(TMP_DIR)/dl && \ - cd $(TMP_DIR)/dl && \ - rm -rf $(SUBDIR) && \ - [ \! -d $(SUBDIR) ] && \ - cvs -d $(URL) co $(VERSION) $(SUBDIR) && \ - find $(SUBDIR) -name CVS | xargs rm -rf && \ - echo "Packing checkout..." && \ - $(call dl_pack,$(TMP_DIR)/dl/$(FILE),$(SUBDIR)) && \ - mv $(TMP_DIR)/dl/$(FILE) $(DL_DIR)/; \ - ) + mkdir -p $(TMP_DIR)/dl && \ + cd $(TMP_DIR)/dl && \ + rm -rf $(SUBDIR) && \ + [ \! -d $(SUBDIR) ] && \ + cvs -d $(URL) co $(VERSION) $(SUBDIR) && \ + find $(SUBDIR) -name CVS | xargs rm -rf && \ + echo "Packing checkout..." && \ + $(call dl_pack,$(TMP_DIR)/dl/$(FILE),$(SUBDIR)) && \ + mv $(TMP_DIR)/dl/$(FILE) $(DL_DIR)/; \ + ) endef - define DownloadMethod/svn $(call wrap_mirror, \ echo "Checking out files from the svn repository..."; \ @@ -93,6 +92,21 @@ define DownloadMethod/git ) endef +define DownloadMethod/bzr + $(call wrap_mirror, \ + echo "Checking out files from the bzr repository..."; \ + mkdir -p $(TMP_DIR)/dl && \ + cd $(TMP_DIR)/dl && \ + rm -rf $(SUBDIR) && \ + [ \! -d $(SUBDIR) ] && \ + bzr co --lightweight -r$(VERSION) $(URL) $(SUBDIR) && \ + find $(SUBDIR) -name .bzr | xargs rm -rf && \ + echo "Packing checkout..." && \ + $(call dl_pack,$(TMP_DIR)/dl/$(FILE),$(SUBDIR)) && \ + mv $(TMP_DIR)/dl/$(FILE) $(DL_DIR)/; \ + ) +endef + define DownloadMethod/hg $(call wrap_mirror, \ echo "Checking out files from the hg repository..."; \ @@ -111,6 +125,7 @@ endef Validate/cvs=VERSION SUBDIR Validate/svn=VERSION SUBDIR Validate/git=VERSION SUBDIR +Validate/bzr=VERSION SUBDIR Validate/hg=VERSION SUBDIR define Download/Defaults diff --git a/include/kernel-build.mk b/include/kernel-build.mk index 62140588d..7c5d1fbe9 100644 --- a/include/kernel-build.mk +++ b/include/kernel-build.mk @@ -106,7 +106,6 @@ define BuildKernel $(_SINGLE)$(MAKE) -C $(LINUX_DIR) $(KERNEL_MAKEOPTS) $$@ $(SCRIPT_DIR)/kconfig.pl '>' $(if $(LINUX_SUBCONFIG),'+' $(GENERIC_LINUX_CONFIG) $(LINUX_CONFIG),$(GENERIC_LINUX_CONFIG)) \ $(LINUX_DIR)/.config > $(if $(LINUX_SUBCONFIG),$(LINUX_SUBCONFIG),$(LINUX_CONFIG)) - LC_ALL='' sort $(if $(LINUX_SUBCONFIG),$(LINUX_SUBCONFIG),$(LINUX_CONFIG)) -o $(if $(LINUX_SUBCONFIG),$(LINUX_SUBCONFIG),$(LINUX_CONFIG)) $(Kernel/Configure) install: $(LINUX_DIR)/.image diff --git a/include/kernel-version.mk b/include/kernel-version.mk index 1d259e38d..5f05cf862 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -1,12 +1,12 @@ # Use the default kernel version if the Makefile doesn't override it ifeq ($(KERNEL),2.4) - LINUX_VERSION?=2.4.37.5 + LINUX_VERSION?=2.4.37.9 endif LINUX_RELEASE?=1 -ifeq ($(LINUX_VERSION),2.4.37.5) - LINUX_KERNEL_MD5SUM:=cb221187422acaf6c63a40c646e5e476 +ifeq ($(LINUX_VERSION),2.4.37.9) + LINUX_KERNEL_MD5SUM:=b85b8962840c13f17f944e7b1890f8f8 endif ifeq ($(LINUX_VERSION),2.6.25.20) LINUX_KERNEL_MD5SUM:=0da698edccf03e2235abc2830a495114 diff --git a/include/netfilter.mk b/include/netfilter.mk index 9eeee4f6e..c8347936d 100644 --- a/include/netfilter.mk +++ b/include/netfilter.mk @@ -91,6 +91,7 @@ $(eval $(if $(NF_KMOD),$(call nf_add,IPT_CONNTRACK,CONFIG_NF_CONNTRACK_IPV4, $(P $(eval $(call nf_add,IPT_CONNTRACK,CONFIG_IP_NF_MATCH_STATE, $(P_V4)ipt_state)) $(eval $(call nf_add,IPT_CONNTRACK,CONFIG_NETFILTER_XT_MATCH_STATE, $(P_XT)xt_state)) $(eval $(call nf_add,IPT_CONNTRACK,CONFIG_IP_NF_RAW, $(P_V4)iptable_raw)) +$(eval $(call nf_add,IPT_CONNTRACK,CONFIG_IP_NF_TARGET_NOTRACK, $(P_V4)ipt_NOTRACK)) $(eval $(call nf_add,IPT_CONNTRACK,CONFIG_NETFILTER_XT_TARGET_NOTRACK, $(P_XT)xt_NOTRACK)) diff --git a/include/package-debug.mk b/include/package-debug.mk deleted file mode 100644 index 2a85bfebb..000000000 --- a/include/package-debug.mk +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (C) 2006,2007 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -ifeq ($(DUMP),) - define BuildTarget/debug - - DEBUG_STAMP_$(1) := $(DEBUG_DIR)/stamp/$(1) - - ifdef Package/$(1)/install - ifneq ($(CONFIG_PACKAGE_$(1))$(SDK)$(DEVELOPER),) - compile: $$(DEBUG_STAMP_$(1)) - endif - endif - - $$(DEBUG_STAMP_$(1)): $(PKG_BUILD_DIR)/.built - mkdir -p $(DEBUG_DIR)/stamp - $(call Package/$(1)/install,$(DEBUG_DIR)) - touch $$(DEBUG_STAMP_$(1)) - - - endef -endif diff --git a/include/package.mk b/include/package.mk index 90aa51c59..f48c79057 100644 --- a/include/package.mk +++ b/include/package.mk @@ -26,7 +26,6 @@ include $(INCLUDE_DIR)/quilt.mk include $(INCLUDE_DIR)/package-defaults.mk include $(INCLUDE_DIR)/package-dumpinfo.mk include $(INCLUDE_DIR)/package-ipkg.mk -include $(INCLUDE_DIR)/package-debug.mk include $(INCLUDE_DIR)/package-bin.mk include $(INCLUDE_DIR)/autotools.mk @@ -179,7 +178,7 @@ endif $(Dumpinfo/Package), \ $(foreach target, \ $(if $(Package/$(1)/targets),$(Package/$(1)/targets), \ - $(if $(PKG_TARGETS),$(PKG_TARGETS), ipkg $(if $(CONFIG_DEBUG_DIR),debug)) \ + $(if $(PKG_TARGETS),$(PKG_TARGETS), ipkg) \ ), $(BuildTarget/$(target)) \ ) \ ) diff --git a/package/busybox/Makefile b/package/busybox/Makefile index 43da0a48d..714d0c465 100644 --- a/package/busybox/Makefile +++ b/package/busybox/Makefile @@ -70,6 +70,7 @@ define Build/Compile KBUILD_HAVE_NLS=no \ EXTRA_CFLAGS="$(TARGET_CFLAGS)" \ ARCH="$(ARCH)" \ + SKIP_STRIP=y \ all rm -rf $(PKG_INSTALL_DIR) $(FIND) $(PKG_BUILD_DIR) -lname "*busybox" -exec rm \{\} \; @@ -78,7 +79,6 @@ define Build/Compile CROSS_COMPILE="$(TARGET_CROSS)" \ EXTRA_CFLAGS="$(TARGET_CFLAGS)" \ ARCH="$(ARCH)" \ - IPKG_ARCH="$(ARCH)" \ CONFIG_PREFIX="$(PKG_INSTALL_DIR)" \ install endef diff --git a/package/busybox/patches/250-ash_export-n.patch b/package/busybox/patches/250-ash_export-n.patch index 6a420e221..92b198ce5 100644 --- a/package/busybox/patches/250-ash_export-n.patch +++ b/package/busybox/patches/250-ash_export-n.patch @@ -1,6 +1,6 @@ --- a/shell/ash.c +++ b/shell/ash.c -@@ -12360,8 +12360,17 @@ exportcmd(int argc UNUSED_PARAM, char ** +@@ -12351,8 +12351,17 @@ exportcmd(int argc UNUSED_PARAM, char ** const char *p; char **aptr; int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT; @@ -19,7 +19,7 @@ aptr = argptr; name = *aptr; if (name) { -@@ -12373,10 +12382,12 @@ exportcmd(int argc UNUSED_PARAM, char ** +@@ -12364,10 +12373,12 @@ exportcmd(int argc UNUSED_PARAM, char ** vp = *findvar(hashvar(name), name); if (vp) { vp->flags |= flag; diff --git a/package/busybox/patches/510-awk_include.patch b/package/busybox/patches/510-awk_include.patch index 50f6cc549..b9d7d7137 100644 --- a/package/busybox/patches/510-awk_include.patch +++ b/package/busybox/patches/510-awk_include.patch @@ -34,7 +34,7 @@ chain_group(); clear_array(ahash); -@@ -2408,7 +2414,8 @@ static var *evaluate(node *op, var *res) +@@ -2410,7 +2416,8 @@ static var *evaluate(node *op, var *res) break; case XC( OC_FUNC ): @@ -44,7 +44,7 @@ syntax_error(EMSG_UNDEF_FUNC); X.v = R.v = nvalloc(op->r.f->nargs+1); -@@ -2425,7 +2432,10 @@ static var *evaluate(node *op, var *res) +@@ -2427,7 +2434,10 @@ static var *evaluate(node *op, var *res) fnargs = X.v; L.s = g_progname; @@ -56,7 +56,7 @@ g_progname = L.s; nvfree(fnargs); -@@ -2788,6 +2798,143 @@ static rstream *next_input_file(void) +@@ -2790,6 +2800,143 @@ static rstream *next_input_file(void) #undef files_happen } @@ -200,7 +200,7 @@ int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int awk_main(int argc, char **argv) { -@@ -2853,6 +3000,9 @@ int awk_main(int argc, char **argv) +@@ -2855,6 +3002,9 @@ int awk_main(int argc, char **argv) *s1 = '='; } } diff --git a/package/busybox/patches/910-insmod-q-flag.patch b/package/busybox/patches/910-insmod-q-flag.patch new file mode 100644 index 000000000..846b3df56 --- /dev/null +++ b/package/busybox/patches/910-insmod-q-flag.patch @@ -0,0 +1,33 @@ +--- a/modutils/insmod.c ++++ b/modutils/insmod.c +@@ -107,7 +107,7 @@ int insmod_main(int argc, char **argv) M + int insmod_main(int argc UNUSED_PARAM, char **argv) + { + char *filename; +- int rc; ++ int rc, opt; + + /* Compat note: + * 2.6 style insmod has no options and required filename +@@ -117,10 +117,8 @@ int insmod_main(int argc UNUSED_PARAM, c + * or in $MODPATH. + */ + +- IF_FEATURE_2_4_MODULES( +- getopt32(argv, INSMOD_OPTS INSMOD_ARGS); +- argv += optind - 1; +- ); ++ opt = getopt32(argv, INSMOD_OPTS, NULL, NULL); ++ argv += optind - 1; + + filename = *++argv; + if (!filename) +@@ -131,7 +129,7 @@ int insmod_main(int argc UNUSED_PARAM, c + goto done; + + rc = bb_init_module(g_filename, parse_cmdline_module_options(argv)); +- if (rc) ++ if (rc && !(opt & INSMOD_OPT_SILENT)) + bb_error_msg("can't insert '%s': %s", filename, moderror(rc)); + free (g_filename); + diff --git a/package/carl9170/Makefile b/package/carl9170/Makefile index a27292486..823838986 100644 --- a/package/carl9170/Makefile +++ b/package/carl9170/Makefile @@ -9,13 +9,13 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=carl9170 -PKG_VERSION:=0.9.9.1 +PKG_VERSION:=1.0.1.1 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:=@KERNEL/linux/kernel/people/chr/carl9170/$(PKG_VERSION) \ @KERNEL/linux/kernel/people/chr/carl9170/old/$(PKG_VERSION) -PKG_MD5SUM:=122610b254125d93c7f64cc559d3341a +PKG_MD5SUM:=8abbb4ae09a45a82af6f63cb65c7e2d8 include $(INCLUDE_DIR)/package.mk diff --git a/package/carl9170/patches/120-compile_fix.patch b/package/carl9170/patches/120-compile_fix.patch new file mode 100644 index 000000000..00f0fba84 --- /dev/null +++ b/package/carl9170/patches/120-compile_fix.patch @@ -0,0 +1,13 @@ +--- a/drivers/net/wireless/ath/carl9170/fw.c ++++ b/drivers/net/wireless/ath/carl9170/fw.c +@@ -185,8 +185,10 @@ static int ar9170_fw_check(struct ar9170 + if (SUPP(CARL9170FW_WLANTX_CAB)) + ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); + ++#ifdef CONFIG_CARL9170_WPS_BUTTON + if (!SUPP(CARL9170FW_GPIO_INTERRUPT)) + ar->has_wps_button = false; ++#endif + + #undef SUPPORTED + return 0; diff --git a/package/firewall/files/uci_firewall.sh b/package/firewall/files/uci_firewall.sh index 207dcd8df..4921b91ba 100755 --- a/package/firewall/files/uci_firewall.sh +++ b/package/firewall/files/uci_firewall.sh @@ -355,18 +355,18 @@ fw_redirect() { src_port_first=${src_port%-*} src_port_last=${src_port#*-} - [ "$src_port_first" -ne "$src_port_last" ] && { \ + [ "$src_port_first" != "$src_port_last" ] && { \ src_port="$src_port_first:$src_port_last"; } src_dport_first=${src_dport%-*} src_dport_last=${src_dport#*-} - [ "$src_dport_first" -ne "$src_dport_last" ] && { \ + [ "$src_dport_first" != "$src_dport_last" ] && { \ src_dport="$src_dport_first:$src_dport_last"; } dest_port2=${dest_port:-$src_dport} dest_port_first=${dest_port2%-*} dest_port_last=${dest_port2#*-} - [ "$dest_port_first" -ne "$dest_port_last" ] && { \ + [ "$dest_port_first" != "$dest_port_last" ] && { \ dest_port2="$dest_port_first:$dest_port_last"; } add_rule() { diff --git a/package/grub/patches/010-fixes-1.patch b/package/grub/patches/010-fixes-1.patch index 6628b7382..91a9e2190 100644 --- a/package/grub/patches/010-fixes-1.patch +++ b/package/grub/patches/010-fixes-1.patch @@ -17,9 +17,8 @@ Description: Contains various fixes and enhancements http://trac.cross-lfs.org/browser/trunk/patches/grub-0.97-fixes-1.patch -diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 ---- grub-0.97.orig/aclocal.m4 2005-05-07 19:41:18.000000000 -0700 -+++ grub-0.97/aclocal.m4 2006-07-04 00:08:22.000000000 -0700 +--- a/aclocal.m4 ++++ b/aclocal.m4 @@ -1,7 +1,7 @@ -# generated automatically by aclocal 1.9.4 -*- Autoconf -*- +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- @@ -60,7 +59,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- -@@ -40,26 +28,15 @@ +@@ -40,26 +28,15 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api # Call AM_AUTOMAKE_VERSION so it can be traced. # This function is AC_REQUIREd by AC_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], @@ -94,7 +93,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to -@@ -106,26 +83,16 @@ +@@ -106,26 +83,16 @@ AC_PREREQ([2.50])dnl am_aux_dir=`cd $ac_aux_dir && pwd` ]) @@ -129,7 +128,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- -@@ -149,26 +116,15 @@ +@@ -149,26 +116,15 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) @@ -162,7 +161,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, -@@ -177,7 +133,6 @@ +@@ -177,7 +133,6 @@ fi])]) # CC etc. in the Makefile, will ask for an AC_PROG_CC use... @@ -170,7 +169,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. -@@ -317,27 +272,16 @@ +@@ -317,27 +272,16 @@ AM_CONDITIONAL([AMDEP], [test "x$enable_ AC_SUBST([AMDEPBACKSLASH]) ]) @@ -206,7 +205,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ -@@ -396,30 +340,19 @@ +@@ -396,30 +340,19 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS] [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) @@ -246,7 +245,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) -@@ -521,51 +454,27 @@ +@@ -521,51 +454,27 @@ for _am_header in $config_headers :; do done echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) @@ -310,7 +309,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. -@@ -580,28 +489,17 @@ +@@ -580,28 +489,17 @@ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) @@ -346,7 +345,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 AC_DEFUN([AM_MAINTAINER_MODE], [AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) -@@ -620,26 +518,15 @@ +@@ -620,26 +518,15 @@ AC_DEFUN([AM_MAINTAINER_MODE], AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) @@ -380,7 +379,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # AM_MAKE_INCLUDE() # ----------------- -@@ -683,27 +570,16 @@ +@@ -683,27 +570,16 @@ AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) @@ -416,7 +415,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ -@@ -729,27 +605,16 @@ +@@ -729,27 +605,16 @@ else fi ]) @@ -451,7 +450,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories # created by `make install' are always world readable, even if the # installer happens to have an overly restrictive umask (e.g. 077). -@@ -803,26 +668,15 @@ +@@ -803,26 +668,15 @@ else fi AC_SUBST([mkdir_p])]) @@ -485,7 +484,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # _AM_MANGLE_OPTION(NAME) # ----------------------- -@@ -847,28 +701,16 @@ +@@ -847,28 +701,16 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) @@ -522,7 +521,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # AM_SANITY_CHECK # --------------- -@@ -911,25 +753,14 @@ +@@ -911,25 +753,14 @@ Check your system clock]) fi AC_MSG_RESULT(yes)]) @@ -555,7 +554,7 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip -@@ -952,25 +783,13 @@ +@@ -952,25 +783,13 @@ AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Check how to create a tarball. -*- Autoconf -*- @@ -587,9 +586,8 @@ diff -Naur grub-0.97.orig/aclocal.m4 grub-0.97/aclocal.m4 # _AM_PROG_TAR(FORMAT) # -------------------- -diff -Naur grub-0.97.orig/ChangeLog grub-0.97/ChangeLog ---- grub-0.97.orig/ChangeLog 2005-05-07 19:47:02.000000000 -0700 -+++ grub-0.97/ChangeLog 2006-07-04 00:01:50.000000000 -0700 +--- a/ChangeLog ++++ b/ChangeLog @@ -1,3 +1,51 @@ +2006-05-02 Pavel Roskin + @@ -642,10 +640,9 @@ diff -Naur grub-0.97.orig/ChangeLog grub-0.97/ChangeLog 2005-05-08 Yoshinori K. Okuji * configure.ac (AC_INIT): Upgraded to 0.97. -diff -Naur grub-0.97.orig/configure grub-0.97/configure ---- grub-0.97.orig/configure 2005-05-07 19:48:12.000000000 -0700 -+++ grub-0.97/configure 2006-07-04 00:08:05.000000000 -0700 -@@ -311,7 +311,7 @@ +--- a/configure ++++ b/configure +@@ -311,7 +311,7 @@ ac_includes_default="\ # include #endif" @@ -654,7 +651,7 @@ diff -Naur grub-0.97.orig/configure grub-0.97/configure ac_subst_files='' # Initialize some variables set by options. -@@ -914,6 +914,7 @@ +@@ -914,6 +914,7 @@ Optional Features: set the default memory location for WD/SMC --enable-cs-scan=LIST probe for CS89x0 base address using LIST --enable-diskless enable diskless support @@ -662,7 +659,7 @@ diff -Naur grub-0.97.orig/configure grub-0.97/configure --disable-hercules disable hercules terminal support --disable-serial disable serial terminal support --enable-serial-speed-simulation -@@ -5966,6 +5967,22 @@ +@@ -5966,6 +5967,22 @@ else fi @@ -685,7 +682,7 @@ diff -Naur grub-0.97.orig/configure grub-0.97/configure # Check whether --enable-hercules or --disable-hercules was given. if test "${enable_hercules+set}" = set; then enableval="$enable_hercules" -@@ -6270,6 +6287,13 @@ +@@ -6270,6 +6287,13 @@ echo "$as_me: error: conditional \"DISKL Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi @@ -699,7 +696,7 @@ diff -Naur grub-0.97.orig/configure grub-0.97/configure if test -z "${HERCULES_SUPPORT_TRUE}" && test -z "${HERCULES_SUPPORT_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"HERCULES_SUPPORT\" was never defined. Usually this means the macro was only invoked conditionally." >&5 -@@ -6907,6 +6931,8 @@ +@@ -6907,6 +6931,8 @@ s,@NETBOOT_SUPPORT_TRUE@,$NETBOOT_SUPPOR s,@NETBOOT_SUPPORT_FALSE@,$NETBOOT_SUPPORT_FALSE,;t t s,@DISKLESS_SUPPORT_TRUE@,$DISKLESS_SUPPORT_TRUE,;t t s,@DISKLESS_SUPPORT_FALSE@,$DISKLESS_SUPPORT_FALSE,;t t @@ -708,10 +705,9 @@ diff -Naur grub-0.97.orig/configure grub-0.97/configure s,@HERCULES_SUPPORT_TRUE@,$HERCULES_SUPPORT_TRUE,;t t s,@HERCULES_SUPPORT_FALSE@,$HERCULES_SUPPORT_FALSE,;t t s,@SERIAL_SUPPORT_TRUE@,$SERIAL_SUPPORT_TRUE,;t t -diff -Naur grub-0.97.orig/configure.ac grub-0.97/configure.ac ---- grub-0.97.orig/configure.ac 2005-05-07 19:36:03.000000000 -0700 -+++ grub-0.97/configure.ac 2006-07-03 23:58:41.000000000 -0700 -@@ -595,6 +595,11 @@ +--- a/configure.ac ++++ b/configure.ac +@@ -595,6 +595,11 @@ AC_ARG_ENABLE(diskless, [ --enable-diskless enable diskless support]) AM_CONDITIONAL(DISKLESS_SUPPORT, test "x$enable_diskless" = xyes) @@ -723,9 +719,8 @@ diff -Naur grub-0.97.orig/configure.ac grub-0.97/configure.ac dnl Hercules terminal AC_ARG_ENABLE(hercules, [ --disable-hercules disable hercules terminal support]) -diff -Naur grub-0.97.orig/docs/grub.8 grub-0.97/docs/grub.8 ---- grub-0.97.orig/docs/grub.8 2005-05-07 19:48:56.000000000 -0700 -+++ grub-0.97/docs/grub.8 2006-07-04 00:01:50.000000000 -0700 +--- a/docs/grub.8 ++++ b/docs/grub.8 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23. -.TH GRUB "8" "May 2005" "grub (GNU GRUB 0.97)" FSF @@ -733,10 +728,9 @@ diff -Naur grub-0.97.orig/docs/grub.8 grub-0.97/docs/grub.8 .SH NAME grub \- the grub shell .SH SYNOPSIS -diff -Naur grub-0.97.orig/docs/grub.texi grub-0.97/docs/grub.texi ---- grub-0.97.orig/docs/grub.texi 2005-05-07 19:59:59.000000000 -0700 -+++ grub-0.97/docs/grub.texi 2006-07-04 00:00:54.000000000 -0700 -@@ -2199,6 +2199,7 @@ +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -2199,6 +2199,7 @@ Commands usable anywhere in the menu and * rarp:: Initialize a network device via RARP * serial:: Set up a serial device * setkey:: Configure the key map @@ -744,7 +738,7 @@ diff -Naur grub-0.97.orig/docs/grub.texi grub-0.97/docs/grub.texi * terminal:: Choose a terminal * terminfo:: Define escape sequences for a terminal * tftpserver:: Specify a TFTP server -@@ -2578,6 +2579,16 @@ +@@ -2578,6 +2579,16 @@ character each of the symbols correspond @end deffn @@ -761,7 +755,7 @@ diff -Naur grub-0.97.orig/docs/grub.texi grub-0.97/docs/grub.texi @node terminal @subsection terminal -@@ -2685,6 +2696,7 @@ +@@ -2685,6 +2696,7 @@ you forget a command, you can run the co * module:: Load a module * modulenounzip:: Load a module without decompression * pause:: Wait for a key press @@ -769,7 +763,7 @@ diff -Naur grub-0.97.orig/docs/grub.texi grub-0.97/docs/grub.texi * quit:: Exit from the grub shell * reboot:: Reboot your computer * read:: Read data from memory -@@ -3091,6 +3103,16 @@ +@@ -3091,6 +3103,16 @@ change floppies. @end deffn @@ -786,9 +780,8 @@ diff -Naur grub-0.97.orig/docs/grub.texi grub-0.97/docs/grub.texi @node quit @subsection quit -diff -Naur grub-0.97.orig/docs/multiboot.texi grub-0.97/docs/multiboot.texi ---- grub-0.97.orig/docs/multiboot.texi 2003-07-09 04:45:36.000000000 -0700 -+++ grub-0.97/docs/multiboot.texi 2006-07-04 00:01:50.000000000 -0700 +--- a/docs/multiboot.texi ++++ b/docs/multiboot.texi @@ -25,7 +25,7 @@ @ifinfo Copyright @copyright{} 1995, 96 Bryan Ford @@ -798,7 +791,7 @@ diff -Naur grub-0.97.orig/docs/multiboot.texi grub-0.97/docs/multiboot.texi Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice -@@ -57,7 +57,7 @@ +@@ -57,7 +57,7 @@ into another language, under the above c @vskip 0pt plus 1filll Copyright @copyright{} 1995, 96 Bryan Ford Copyright @copyright{} 1995, 96 Erich Stefan Boleyn @@ -807,7 +800,7 @@ diff -Naur grub-0.97.orig/docs/multiboot.texi grub-0.97/docs/multiboot.texi Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice -@@ -80,7 +80,7 @@ +@@ -80,7 +80,7 @@ into another language, under the above c @top Multiboot Specification This file documents Multiboot Specification, the proposal for the boot @@ -816,7 +809,7 @@ diff -Naur grub-0.97.orig/docs/multiboot.texi grub-0.97/docs/multiboot.texi @end ifnottex @menu -@@ -426,7 +426,7 @@ +@@ -426,7 +426,7 @@ mode table (@pxref{Boot information form kernel. If bit 16 in the @samp{flags} word is set, then the fields at offsets @@ -825,7 +818,7 @@ diff -Naur grub-0.97.orig/docs/multiboot.texi grub-0.97/docs/multiboot.texi them instead of the fields in the actual executable header to calculate where to load the OS image. This information does not need to be provided if the kernel image is in @sc{elf} format, but it @emph{must} -@@ -677,7 +677,7 @@ +@@ -677,7 +677,7 @@ follows: @example @group +-------+-------+-------+-------+ @@ -834,7 +827,7 @@ diff -Naur grub-0.97.orig/docs/multiboot.texi grub-0.97/docs/multiboot.texi +-------+-------+-------+-------+ @end group @end example -@@ -1199,6 +1199,13 @@ +@@ -1199,6 +1199,13 @@ The maintainer changes to the GNU GRUB m @email{bug-grub@@gnu.org}, from Bryan Ford and Erich Stefan Boleyn. @end itemize @@ -848,10 +841,9 @@ diff -Naur grub-0.97.orig/docs/multiboot.texi grub-0.97/docs/multiboot.texi @item 0.6 @itemize @bullet @item -diff -Naur grub-0.97.orig/grub/asmstub.c grub-0.97/grub/asmstub.c ---- grub-0.97.orig/grub/asmstub.c 2005-02-16 12:45:14.000000000 -0800 -+++ grub-0.97/grub/asmstub.c 2006-07-04 00:01:50.000000000 -0700 -@@ -42,6 +42,12 @@ +--- a/grub/asmstub.c ++++ b/grub/asmstub.c +@@ -42,6 +42,12 @@ int grub_stage2 (void); #include #include #include @@ -864,7 +856,7 @@ diff -Naur grub-0.97.orig/grub/asmstub.c grub-0.97/grub/asmstub.c #ifdef __linux__ # include /* ioctl */ -@@ -55,6 +61,10 @@ +@@ -55,6 +61,10 @@ int grub_stage2 (void); # endif /* ! BLKFLSBUF */ #endif /* __linux__ */ @@ -875,7 +867,7 @@ diff -Naur grub-0.97.orig/grub/asmstub.c grub-0.97/grub/asmstub.c /* We want to prevent any circularararity in our stubs, as well as libc name clashes. */ #define WITHOUT_LIBC_STUBS 1 -@@ -144,6 +154,22 @@ +@@ -144,6 +154,22 @@ grub_stage2 (void) assert (grub_scratch_mem == 0); scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15); assert (scratch); @@ -898,7 +890,7 @@ diff -Naur grub-0.97.orig/grub/asmstub.c grub-0.97/grub/asmstub.c grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4); /* FIXME: simulate the memory holes using mprot, if available. */ -@@ -777,7 +803,39 @@ +@@ -777,7 +803,39 @@ get_diskinfo (int drive, struct geometry /* Open read/write, or read-only if that failed. */ if (! read_only) @@ -939,10 +931,9 @@ diff -Naur grub-0.97.orig/grub/asmstub.c grub-0.97/grub/asmstub.c if (disks[drive].flags == -1) { -diff -Naur grub-0.97.orig/grub/main.c grub-0.97/grub/main.c ---- grub-0.97.orig/grub/main.c 2003-07-09 04:45:36.000000000 -0700 -+++ grub-0.97/grub/main.c 2006-07-04 00:01:50.000000000 -0700 -@@ -32,6 +32,7 @@ +--- a/grub/main.c ++++ b/grub/main.c +@@ -32,6 +32,7 @@ int grub_stage2 (void); #define WITHOUT_LIBC_STUBS 1 #include #include @@ -950,7 +941,7 @@ diff -Naur grub-0.97.orig/grub/main.c grub-0.97/grub/main.c char *program_name = 0; int use_config_file = 1; -@@ -192,6 +193,12 @@ +@@ -192,6 +193,12 @@ main (int argc, char **argv) perror ("strtoul"); exit (1); } @@ -963,10 +954,9 @@ diff -Naur grub-0.97.orig/grub/main.c grub-0.97/grub/main.c break; case OPT_NO_CONFIG_FILE: -diff -Naur grub-0.97.orig/lib/device.c grub-0.97/lib/device.c ---- grub-0.97.orig/lib/device.c 2005-03-27 15:14:25.000000000 -0800 -+++ grub-0.97/lib/device.c 2006-07-04 00:00:44.000000000 -0700 -@@ -131,6 +131,152 @@ +--- a/lib/device.c ++++ b/lib/device.c +@@ -131,6 +131,152 @@ get_kfreebsd_version () #include #include @@ -1119,7 +1109,7 @@ diff -Naur grub-0.97.orig/lib/device.c grub-0.97/lib/device.c /* Get the geometry of a drive DRIVE. */ void get_drive_geometry (struct geometry *geom, char **map, int drive) -@@ -151,21 +297,16 @@ +@@ -151,21 +297,16 @@ get_drive_geometry (struct geometry *geo #if defined(__linux__) /* Linux */ { @@ -1144,7 +1134,7 @@ diff -Naur grub-0.97.orig/lib/device.c grub-0.97/lib/device.c goto success; } -@@ -403,6 +544,18 @@ +@@ -403,6 +544,18 @@ get_dac960_disk_name (char *name, int co } static void @@ -1163,7 +1153,7 @@ diff -Naur grub-0.97.orig/lib/device.c grub-0.97/lib/device.c get_ataraid_disk_name (char *name, int unit) { sprintf (name, "/dev/ataraid/d%c", unit + '0'); -@@ -801,6 +954,74 @@ +@@ -801,6 +954,74 @@ init_device_map (char ***map, const char } } } @@ -1238,7 +1228,7 @@ diff -Naur grub-0.97.orig/lib/device.c grub-0.97/lib/device.c #endif /* __linux__ */ /* OK, close the device map file if opened. */ -@@ -844,6 +1065,7 @@ +@@ -844,6 +1065,7 @@ write_to_partition (char **map, int driv { char dev[PATH_MAX]; /* XXX */ int fd; @@ -1246,7 +1236,7 @@ diff -Naur grub-0.97.orig/lib/device.c grub-0.97/lib/device.c if ((partition & 0x00FF00) != 0x00FF00) { -@@ -861,8 +1083,14 @@ +@@ -861,8 +1083,14 @@ write_to_partition (char **map, int driv if (strcmp (dev + strlen(dev) - 5, "/disc") == 0) strcpy (dev + strlen(dev) - 5, "/part"); } @@ -1263,7 +1253,7 @@ diff -Naur grub-0.97.orig/lib/device.c grub-0.97/lib/device.c /* Open the partition. */ fd = open (dev, O_RDWR); if (fd < 0) -@@ -870,35 +1098,13 @@ +@@ -870,35 +1098,13 @@ write_to_partition (char **map, int driv errnum = ERR_NO_PART; return 0; } @@ -1304,10 +1294,9 @@ diff -Naur grub-0.97.orig/lib/device.c grub-0.97/lib/device.c if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE)) { -diff -Naur grub-0.97.orig/stage2/asm.S grub-0.97/stage2/asm.S ---- grub-0.97.orig/stage2/asm.S 2004-06-19 09:55:22.000000000 -0700 -+++ grub-0.97/stage2/asm.S 2006-07-04 00:01:19.000000000 -0700 -@@ -1651,7 +1651,29 @@ +--- a/stage2/asm.S ++++ b/stage2/asm.S +@@ -1651,7 +1651,29 @@ ENTRY(gateA20) jnz 3f ret @@ -1338,7 +1327,7 @@ diff -Naur grub-0.97.orig/stage2/asm.S grub-0.97/stage2/asm.S pushl %eax call gloop1 -@@ -1661,9 +1683,12 @@ +@@ -1661,9 +1683,12 @@ ENTRY(gateA20) gloopint1: inb $K_STATUS @@ -1351,7 +1340,7 @@ diff -Naur grub-0.97.orig/stage2/asm.S grub-0.97/stage2/asm.S movb $KB_OUTPUT_MASK, %al cmpb $0, 0x8(%esp) jz gdoit -@@ -1684,6 +1709,8 @@ +@@ -1684,6 +1709,8 @@ gdoit: gloop1: inb $K_STATUS @@ -1360,7 +1349,7 @@ diff -Naur grub-0.97.orig/stage2/asm.S grub-0.97/stage2/asm.S andb $K_IBUF_FUL, %al jnz gloop1 -@@ -1991,6 +2018,11 @@ +@@ -1991,6 +2018,11 @@ ENTRY(ascii_key_map) ENTRY(console_getkey) push %ebp @@ -1372,7 +1361,7 @@ diff -Naur grub-0.97.orig/stage2/asm.S grub-0.97/stage2/asm.S call EXT_C(prot_to_real) .code16 -@@ -2216,7 +2248,304 @@ +@@ -2216,7 +2248,304 @@ ENTRY(console_setcursor) pop %ebx pop %ebp ret @@ -1678,9 +1667,8 @@ diff -Naur grub-0.97.orig/stage2/asm.S grub-0.97/stage2/asm.S /* * getrtsecs() * if a seconds value can be read, read it and return it (BCD), -diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c ---- grub-0.97.orig/stage2/boot.c 2004-03-30 03:44:08.000000000 -0800 -+++ grub-0.97/stage2/boot.c 2006-07-04 00:01:50.000000000 -0700 +--- a/stage2/boot.c ++++ b/stage2/boot.c @@ -1,7 +1,7 @@ /* boot.c - load and bootstrap a kernel */ /* @@ -1690,7 +1678,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -@@ -29,6 +29,8 @@ +@@ -29,6 +29,8 @@ static int cur_addr; entry_func entry_addr; static struct mod_list mll[99]; static int linux_mem_size; @@ -1699,7 +1687,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c /* * The next two functions, 'load_image' and 'load_module', are the building -@@ -96,7 +98,7 @@ +@@ -96,7 +98,7 @@ load_image (char *kernel, char *arg, ker lh = (struct linux_kernel_header *) buffer; /* ELF loading supported if multiboot, FreeBSD and NetBSD. */ @@ -1708,7 +1696,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c || pu.elf->e_ident[EI_OSABI] == ELFOSABI_FREEBSD || grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0 || suggested_type == KERNEL_TYPE_NETBSD) -@@ -594,6 +596,7 @@ +@@ -594,6 +596,7 @@ load_image (char *kernel, char *arg, ker /* reset this to zero for now */ cur_addr = 0; @@ -1716,7 +1704,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c /* scan for program segments */ for (i = 0; i < pu.elf->e_phnum; i++) -@@ -630,6 +633,8 @@ +@@ -630,6 +633,8 @@ load_image (char *kernel, char *arg, ker /* mark memory as used */ if (cur_addr < memaddr + memsiz) cur_addr = memaddr + memsiz; @@ -1725,7 +1713,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c printf (", <0x%x:0x%x:0x%x>", memaddr, filesiz, memsiz - filesiz); /* increment number of segments */ -@@ -647,6 +652,8 @@ +@@ -647,6 +652,8 @@ load_image (char *kernel, char *arg, ker } } @@ -1734,7 +1722,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c if (! errnum) { if (! loaded) -@@ -824,8 +831,11 @@ +@@ -824,8 +831,11 @@ load_initrd (char *initrd) moveto = (mbi.mem_upper + 0x400) << 10; moveto = (moveto - len) & 0xfffff000; @@ -1748,7 +1736,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c if (moveto + len >= max_addr) moveto = (max_addr - len) & 0xfffff000; -@@ -864,6 +874,129 @@ +@@ -864,6 +874,129 @@ bsd_boot_entry (int flags, int bootdev, } #endif @@ -1878,7 +1866,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c /* * All "*_boot" commands depend on the images being loaded into memory -@@ -877,7 +1010,10 @@ +@@ -877,7 +1010,10 @@ void bsd_boot (kernel_t type, int bootdev, char *arg) { char *str; @@ -1890,7 +1878,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c struct bootinfo bi; #ifdef GRUB_UTIL -@@ -886,8 +1022,21 @@ +@@ -886,8 +1022,21 @@ bsd_boot (kernel_t type, int bootdev, ch stop_floppy (); #endif @@ -1912,7 +1900,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c while (*str) { if (*str == '-') -@@ -910,6 +1059,8 @@ +@@ -910,6 +1059,8 @@ bsd_boot (kernel_t type, int bootdev, ch clval |= RB_GDB; if (*str == 'h') clval |= RB_SERIAL; @@ -1921,7 +1909,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c if (*str == 'm') clval |= RB_MUTE; if (*str == 'r') -@@ -927,14 +1078,17 @@ +@@ -927,14 +1078,17 @@ bsd_boot (kernel_t type, int bootdev, ch if (type == KERNEL_TYPE_FREEBSD) { @@ -1943,7 +1931,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c else bi.bi_kernelname = 0; -@@ -961,6 +1115,30 @@ +@@ -961,6 +1115,30 @@ bsd_boot (kernel_t type, int bootdev, ch bi.bi_basemem = mbi.mem_lower; bi.bi_extmem = extended_memory; @@ -1974,7 +1962,7 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c if (mbi.flags & MB_INFO_AOUT_SYMS) { bi.bi_symtab = mbi.syms.a.addr; -@@ -970,8 +1148,9 @@ +@@ -970,8 +1148,9 @@ bsd_boot (kernel_t type, int bootdev, ch #if 0 else if (mbi.flags & MB_INFO_ELF_SHDR) { @@ -1986,9 +1974,8 @@ diff -Naur grub-0.97.orig/stage2/boot.c grub-0.97/stage2/boot.c } #endif else -diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c ---- grub-0.97.orig/stage2/builtins.c 2005-02-15 13:58:23.000000000 -0800 -+++ grub-0.97/stage2/builtins.c 2006-07-04 00:01:50.000000000 -0700 +--- a/stage2/builtins.c ++++ b/stage2/builtins.c @@ -28,6 +28,10 @@ #include #include @@ -2000,7 +1987,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c #ifdef SUPPORT_NETBOOT # define GRUB 1 # include -@@ -82,6 +86,10 @@ +@@ -82,6 +86,10 @@ static unsigned short bios_drive_map[DRI inside other functions. */ static int configfile_func (char *arg, int flags); @@ -2011,7 +1998,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c /* Initialize the data for builtins. */ void init_builtins (void) -@@ -237,12 +245,22 @@ +@@ -237,12 +245,22 @@ static struct builtin builtin_blocklist static int boot_func (char *arg, int flags) { @@ -2034,7 +2021,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c #ifdef SUPPORT_NETBOOT /* Shut down the networking. */ cleanup_net (); -@@ -306,6 +324,13 @@ +@@ -306,6 +324,13 @@ boot_func (char *arg, int flags) return 1; } @@ -2048,7 +2035,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c return 0; } -@@ -852,6 +877,251 @@ +@@ -852,6 +877,251 @@ static struct builtin builtin_dhcp = }; #endif /* SUPPORT_NETBOOT */ @@ -2300,7 +2287,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c /* displayapm */ static int -@@ -1454,14 +1724,20 @@ +@@ -1454,14 +1724,20 @@ static struct builtin builtin_halt = /* help */ @@ -2326,7 +2313,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0) { all = 1; -@@ -1491,13 +1767,13 @@ +@@ -1491,13 +1767,13 @@ help_func (char *arg, int flags) len = grub_strlen ((*builtin)->short_doc); /* If the length of SHORT_DOC is too long, truncate it. */ @@ -2343,7 +2330,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c grub_putchar (' '); if (! left) -@@ -1546,10 +1822,10 @@ +@@ -1546,10 +1822,10 @@ help_func (char *arg, int flags) int i; /* If LEN is too long, fold DOC. */ @@ -2356,7 +2343,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c if (doc[len - 1] == ' ') break; } -@@ -2323,6 +2599,25 @@ +@@ -2323,6 +2599,25 @@ static struct builtin builtin_ioprobe = "Probe I/O ports used for the drive DRIVE." }; @@ -2382,7 +2369,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c /* kernel */ static int -@@ -3221,7 +3516,102 @@ +@@ -3221,7 +3516,102 @@ static struct builtin builtin_rootnoveri static int savedefault_func (char *arg, int flags) { @@ -2486,7 +2473,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c unsigned long tmp_drive = saved_drive; unsigned long tmp_partition = saved_partition; char *default_file = (char *) DEFAULT_FILE_BUF; -@@ -3300,19 +3690,23 @@ +@@ -3300,19 +3690,23 @@ savedefault_func (char *arg, int flags) disk_read_hook = 0; grub_close (); @@ -2517,7 +2504,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c /* Set up a string to be written. */ grub_memset (buf, '\n', sizeof (buf)); -@@ -3830,15 +4224,15 @@ +@@ -3830,15 +4224,15 @@ setup_func (char *arg, int flags) { char tmp[16]; grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF); @@ -2536,7 +2523,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c } int embed_stage1_5 (char *stage1_5, int drive, int partition) -@@ -4085,7 +4479,7 @@ +@@ -4085,7 +4479,7 @@ static struct builtin builtin_setup = }; @@ -2545,7 +2532,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c /* terminal */ static int terminal_func (char *arg, int flags) -@@ -4244,17 +4638,29 @@ +@@ -4244,17 +4638,29 @@ terminal_func (char *arg, int flags) end: current_term = term_table + default_term; current_term->flags = term_flags; @@ -2580,7 +2567,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c return 0; } -@@ -4264,7 +4670,7 @@ +@@ -4264,7 +4670,7 @@ static struct builtin builtin_terminal = "terminal", terminal_func, BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, @@ -2589,7 +2576,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c "Select a terminal. When multiple terminals are specified, wait until" " you push any key to continue. If both console and serial are specified," " the terminal to which you input a key first will be selected. If no" -@@ -4276,7 +4682,7 @@ +@@ -4276,7 +4682,7 @@ static struct builtin builtin_terminal = " seconds. The option --lines specifies the maximum number of lines." " The option --silent is used to suppress messages." }; @@ -2598,7 +2585,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c #ifdef SUPPORT_SERIAL -@@ -4795,13 +5201,20 @@ +@@ -4795,13 +5201,20 @@ static struct builtin builtin_vbeprobe = /* The table of builtin commands. Sorted in dictionary order. */ struct builtin *builtin_table[] = { @@ -2619,7 +2606,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c &builtin_cmp, &builtin_color, &builtin_configfile, -@@ -4821,6 +5234,9 @@ +@@ -4821,6 +5234,9 @@ struct builtin *builtin_table[] = &builtin_embed, &builtin_fallback, &builtin_find, @@ -2629,7 +2616,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c &builtin_fstest, &builtin_geometry, &builtin_halt, -@@ -4848,6 +5264,7 @@ +@@ -4848,6 +5264,7 @@ struct builtin *builtin_table[] = &builtin_parttype, &builtin_password, &builtin_pause, @@ -2637,7 +2624,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c #ifdef GRUB_UTIL &builtin_quit, #endif /* GRUB_UTIL */ -@@ -4864,9 +5281,13 @@ +@@ -4864,9 +5281,13 @@ struct builtin *builtin_table[] = #endif /* SUPPORT_SERIAL */ &builtin_setkey, &builtin_setup, @@ -2653,7 +2640,7 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c #ifdef SUPPORT_SERIAL &builtin_terminfo, #endif /* SUPPORT_SERIAL */ -@@ -4880,5 +5301,8 @@ +@@ -4880,5 +5301,8 @@ struct builtin *builtin_table[] = &builtin_unhide, &builtin_uppermem, &builtin_vbeprobe, @@ -2662,9 +2649,8 @@ diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c +#endif 0 }; -diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c ---- grub-0.97.orig/stage2/char_io.c 2005-02-01 12:51:23.000000000 -0800 -+++ grub-0.97/stage2/char_io.c 2006-07-03 23:59:27.000000000 -0700 +--- a/stage2/char_io.c ++++ b/stage2/char_io.c @@ -29,12 +29,17 @@ # include #endif @@ -2683,7 +2669,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c console_putchar, console_checkkey, console_getkey, -@@ -43,13 +48,16 @@ +@@ -43,13 +48,16 @@ struct term_entry term_table[] = console_cls, console_setcolorstate, console_setcolor, @@ -2701,7 +2687,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c serial_putchar, serial_checkkey, serial_getkey, -@@ -58,6 +66,8 @@ +@@ -58,6 +66,8 @@ struct term_entry term_table[] = serial_cls, serial_setcolorstate, 0, @@ -2710,7 +2696,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c 0 }, #endif /* SUPPORT_SERIAL */ -@@ -65,6 +75,7 @@ +@@ -65,6 +75,7 @@ struct term_entry term_table[] = { "hercules", 0, @@ -2718,7 +2704,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c hercules_putchar, console_checkkey, console_getkey, -@@ -73,11 +84,30 @@ +@@ -73,11 +84,30 @@ struct term_entry term_table[] = hercules_cls, hercules_setcolorstate, hercules_setcolor, @@ -2751,7 +2737,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c }; /* This must be console. */ -@@ -305,9 +335,10 @@ +@@ -305,9 +335,10 @@ real_get_cmdline (char *prompt, char *cm /* XXX: These should be defined in shared.h, but I leave these here, until this code is freezed. */ @@ -2764,7 +2750,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c int xpos, lpos, c, section; /* The length of PROMPT. */ int plen; -@@ -338,7 +369,7 @@ +@@ -338,7 +369,7 @@ real_get_cmdline (char *prompt, char *cm /* If the cursor is in the first section, display the first section instead of the second. */ @@ -2773,7 +2759,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c cl_refresh (1, 0); else if (xpos - count < 1) cl_refresh (1, 0); -@@ -354,7 +385,7 @@ +@@ -354,7 +385,7 @@ real_get_cmdline (char *prompt, char *cm grub_putchar ('\b'); } else @@ -2782,7 +2768,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c } } -@@ -364,7 +395,7 @@ +@@ -364,7 +395,7 @@ real_get_cmdline (char *prompt, char *cm lpos += count; /* If the cursor goes outside, scroll the screen to the right. */ @@ -2791,7 +2777,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c cl_refresh (1, 0); else { -@@ -383,7 +414,7 @@ +@@ -383,7 +414,7 @@ real_get_cmdline (char *prompt, char *cm } } else @@ -2800,7 +2786,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c } } -@@ -398,14 +429,14 @@ +@@ -398,14 +429,14 @@ real_get_cmdline (char *prompt, char *cm if (full) { /* Recompute the section number. */ @@ -2819,7 +2805,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c pos = 0; grub_putchar ('\r'); -@@ -445,8 +476,8 @@ +@@ -445,8 +476,8 @@ real_get_cmdline (char *prompt, char *cm if (! full) offset = xpos - 1; @@ -2830,7 +2816,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c xpos = lpos + 1 - start; start += offset; } -@@ -471,7 +502,7 @@ +@@ -471,7 +502,7 @@ real_get_cmdline (char *prompt, char *cm /* If the cursor is at the last position, put `>' or a space, depending on if there are more characters in BUF. */ @@ -2839,7 +2825,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c { if (start + len < llen) grub_putchar ('>'); -@@ -488,7 +519,7 @@ +@@ -488,7 +519,7 @@ real_get_cmdline (char *prompt, char *cm grub_putchar ('\b'); } else @@ -2848,7 +2834,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c } /* Initialize the command-line. */ -@@ -518,10 +549,10 @@ +@@ -518,10 +549,10 @@ real_get_cmdline (char *prompt, char *cm llen += l; lpos += l; @@ -2862,7 +2848,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c else cl_refresh (0, l + llen - lpos); } -@@ -533,12 +564,22 @@ +@@ -533,12 +564,22 @@ real_get_cmdline (char *prompt, char *cm grub_memmove (buf + lpos, buf + lpos + count, llen - count + 1); llen -= count; @@ -2887,7 +2873,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c plen = grub_strlen (prompt); llen = grub_strlen (cmdline); -@@ -1006,6 +1047,48 @@ +@@ -1006,6 +1047,48 @@ checkkey (void) } #endif /* ! STAGE1_5 */ @@ -2936,7 +2922,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c /* Display an ASCII character. */ void grub_putchar (int c) -@@ -1034,38 +1117,11 @@ +@@ -1034,38 +1117,11 @@ grub_putchar (int c) if (c == '\n') { @@ -2979,7 +2965,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c } current_term->putchar (c); -@@ -1090,7 +1146,7 @@ +@@ -1090,7 +1146,7 @@ void cls (void) { /* If the terminal is dumb, there is no way to clean the terminal. */ @@ -2988,7 +2974,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c grub_putchar ('\n'); else current_term->cls (); -@@ -1175,13 +1231,13 @@ +@@ -1175,13 +1231,13 @@ grub_strlen (const char *str) #endif /* ! STAGE1_5 */ int @@ -3006,7 +2992,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c { int ret; # if defined(HAVE_START_SYMBOL) -@@ -1192,7 +1248,7 @@ +@@ -1192,7 +1248,7 @@ memcheck (int addr, int len) return ret; } @@ -3015,7 +3001,7 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c { int ret; # if defined(HAVE_END_SYMBOL) -@@ -1217,6 +1273,16 @@ +@@ -1217,6 +1273,16 @@ memcheck (int addr, int len) return ! errnum; } @@ -3032,10 +3018,9 @@ diff -Naur grub-0.97.orig/stage2/char_io.c grub-0.97/stage2/char_io.c void * grub_memmove (void *to, const void *from, int len) { -diff -Naur grub-0.97.orig/stage2/cmdline.c grub-0.97/stage2/cmdline.c ---- grub-0.97.orig/stage2/cmdline.c 2004-08-16 16:23:01.000000000 -0700 -+++ grub-0.97/stage2/cmdline.c 2006-07-03 23:58:41.000000000 -0700 -@@ -50,10 +50,11 @@ +--- a/stage2/cmdline.c ++++ b/stage2/cmdline.c +@@ -50,10 +50,11 @@ skip_to (int after_equal, char *cmdline) void print_cmdline_message (int forever) { @@ -3051,9 +3036,8 @@ diff -Naur grub-0.97.orig/stage2/cmdline.c grub-0.97/stage2/cmdline.c } /* Find the builtin whose command name is COMMAND and return the -diff -Naur grub-0.97.orig/stage2/freebsd.h grub-0.97/stage2/freebsd.h ---- grub-0.97.orig/stage2/freebsd.h 2003-07-09 04:45:52.000000000 -0700 -+++ grub-0.97/stage2/freebsd.h 2006-07-03 23:59:36.000000000 -0700 +--- a/stage2/freebsd.h ++++ b/stage2/freebsd.h @@ -1,7 +1,7 @@ /* @@ -3131,9 +3115,8 @@ diff -Naur grub-0.97.orig/stage2/freebsd.h grub-0.97/stage2/freebsd.h +#define MODINFO_ARGS 0x0006 /* Parameters string */ +#define MODINFO_METADATA 0x8000 /* Module-specfic */ + -diff -Naur grub-0.97.orig/stage2/graphics.c grub-0.97/stage2/graphics.c ---- grub-0.97.orig/stage2/graphics.c 1969-12-31 16:00:00.000000000 -0800 -+++ grub-0.97/stage2/graphics.c 2006-07-03 23:58:41.000000000 -0700 +--- /dev/null ++++ b/stage2/graphics.c @@ -0,0 +1,585 @@ +/* + * graphics.c - graphics mode support for GRUB @@ -3720,9 +3703,8 @@ diff -Naur grub-0.97.orig/stage2/graphics.c grub-0.97/stage2/graphics.c +} + +#endif /* SUPPORT_GRAPHICS */ -diff -Naur grub-0.97.orig/stage2/graphics.h grub-0.97/stage2/graphics.h ---- grub-0.97.orig/stage2/graphics.h 1969-12-31 16:00:00.000000000 -0800 -+++ grub-0.97/stage2/graphics.h 2006-07-03 23:58:41.000000000 -0700 +--- /dev/null ++++ b/stage2/graphics.h @@ -0,0 +1,44 @@ +/* graphics.h - graphics console interface */ +/* @@ -3768,10 +3750,9 @@ diff -Naur grub-0.97.orig/stage2/graphics.h grub-0.97/stage2/graphics.h +extern int view_x0, view_y0, view_x1, view_y1; + +#endif /* GRAPHICS_H */ -diff -Naur grub-0.97.orig/stage2/Makefile.am grub-0.97/stage2/Makefile.am ---- grub-0.97.orig/stage2/Makefile.am 2005-02-02 12:37:35.000000000 -0800 -+++ grub-0.97/stage2/Makefile.am 2006-07-03 23:58:41.000000000 -0700 -@@ -7,7 +7,7 @@ +--- a/stage2/Makefile.am ++++ b/stage2/Makefile.am +@@ -7,7 +7,7 @@ noinst_HEADERS = apic.h defs.h dir.h dis fat.h filesys.h freebsd.h fs.h hercules.h i386-elf.h \ imgact_aout.h iso9660.h jfs.h mb_header.h mb_info.h md5.h \ nbi.h pc_slice.h serial.h shared.h smp-imps.h term.h \ @@ -3780,7 +3761,7 @@ diff -Naur grub-0.97.orig/stage2/Makefile.am grub-0.97/stage2/Makefile.am EXTRA_DIST = setjmp.S apm.S $(noinst_SCRIPTS) # For . -@@ -19,7 +19,7 @@ +@@ -19,7 +19,7 @@ libgrub_a_SOURCES = boot.c builtins.c ch disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \ fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \ fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \ @@ -3789,7 +3770,7 @@ diff -Naur grub-0.97.orig/stage2/Makefile.am grub-0.97/stage2/Makefile.am libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \ -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \ -DFSYS_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \ -@@ -79,8 +79,14 @@ +@@ -79,8 +79,14 @@ else HERCULES_FLAGS = endif @@ -3805,7 +3786,7 @@ diff -Naur grub-0.97.orig/stage2/Makefile.am grub-0.97/stage2/Makefile.am STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000 STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1 -@@ -90,7 +96,8 @@ +@@ -90,7 +96,8 @@ pre_stage2_exec_SOURCES = asm.S bios.c b cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \ fsys_fat.c fsys_ffs.c fsys_iso9660.c fsys_jfs.c fsys_minix.c \ fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c gunzip.c \ @@ -3815,10 +3796,9 @@ diff -Naur grub-0.97.orig/stage2/Makefile.am grub-0.97/stage2/Makefile.am pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK) -diff -Naur grub-0.97.orig/stage2/shared.h grub-0.97/stage2/shared.h ---- grub-0.97.orig/stage2/shared.h 2004-06-19 09:40:09.000000000 -0700 -+++ grub-0.97/stage2/shared.h 2006-07-04 00:01:50.000000000 -0700 -@@ -499,7 +499,11 @@ +--- a/stage2/shared.h ++++ b/stage2/shared.h +@@ -499,7 +499,11 @@ struct vbe_mode unsigned char linear_reserved_field_position; unsigned long max_pixel_clock; @@ -3831,7 +3811,7 @@ diff -Naur grub-0.97.orig/stage2/shared.h grub-0.97/stage2/shared.h } __attribute__ ((packed)); -@@ -792,6 +796,11 @@ +@@ -792,6 +796,11 @@ int getxy (void); /* Set the cursor position. */ void gotoxy (int x, int y); @@ -3843,7 +3823,7 @@ diff -Naur grub-0.97.orig/stage2/shared.h grub-0.97/stage2/shared.h /* Displays an ASCII character. IBM displays will translate some characters to special graphical ones (see the DISP_* constants). */ void grub_putchar (int c); -@@ -871,6 +880,7 @@ +@@ -871,6 +880,7 @@ int grub_sprintf (char *buffer, const ch int grub_tolower (int c); int grub_isspace (int c); int grub_strncat (char *s1, const char *s2, int n); @@ -3851,7 +3831,7 @@ diff -Naur grub-0.97.orig/stage2/shared.h grub-0.97/stage2/shared.h void *grub_memmove (void *to, const void *from, int len); void *grub_memset (void *start, int c, int len); int grub_strncat (char *s1, const char *s2, int n); -@@ -911,7 +921,7 @@ +@@ -911,7 +921,7 @@ int substring (const char *s1, const cha int nul_terminate (char *str); int get_based_digit (int c, int base); int safe_parse_maxint (char **str_ptr, int *myint_ptr); @@ -3860,9 +3840,8 @@ diff -Naur grub-0.97.orig/stage2/shared.h grub-0.97/stage2/shared.h void grub_putstr (const char *str); #ifndef NO_DECOMPRESSION -diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c ---- grub-0.97.orig/stage2/stage2.c 2005-03-19 09:51:57.000000000 -0800 -+++ grub-0.97/stage2/stage2.c 2006-07-04 00:01:50.000000000 -0700 +--- a/stage2/stage2.c ++++ b/stage2/stage2.c @@ -20,6 +20,12 @@ #include #include @@ -3876,7 +3855,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c grub_jmp_buf restart_env; #if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS) -@@ -105,13 +111,13 @@ +@@ -105,13 +111,13 @@ print_entry (int y, int highlight, char if (highlight && current_term->setcolorstate) current_term->setcolorstate (COLOR_STATE_HIGHLIGHT); @@ -3894,7 +3873,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c grub_putchar (DISP_RIGHT); else grub_putchar (*entry++); -@@ -119,7 +125,7 @@ +@@ -119,7 +125,7 @@ print_entry (int y, int highlight, char else grub_putchar (' '); } @@ -3903,7 +3882,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c if (current_term->setcolorstate) current_term->setcolorstate (COLOR_STATE_STANDARD); -@@ -131,7 +137,7 @@ +@@ -131,7 +137,7 @@ print_entries (int y, int size, int firs { int i; @@ -3912,7 +3891,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c if (first) grub_putchar (DISP_UP); -@@ -151,14 +157,14 @@ +@@ -151,14 +157,14 @@ print_entries (int y, int size, int firs menu_entries++; } @@ -3929,7 +3908,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c } static void -@@ -196,30 +202,30 @@ +@@ -196,30 +202,30 @@ print_border (int y, int size) if (current_term->setcolorstate) current_term->setcolorstate (COLOR_STATE_NORMAL); @@ -3965,7 +3944,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c grub_putchar (DISP_HORIZ); grub_putchar (DISP_LR); -@@ -233,6 +239,7 @@ +@@ -233,6 +239,7 @@ run_menu (char *menu_entries, char *conf { int c, time1, time2 = -1, first_entry = 0; char *cur_entry = 0; @@ -3973,7 +3952,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c /* * Main loop for menu UI. -@@ -250,6 +257,22 @@ +@@ -250,6 +257,22 @@ restart: } } @@ -3996,7 +3975,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c /* If the timeout was expired or wasn't set, force to show the menu interface. */ if (grub_timeout < 0) -@@ -302,36 +325,36 @@ +@@ -302,36 +325,36 @@ restart: if (current_term->flags & TERM_DUMB) print_entries_raw (num_entries, first_entry, menu_entries); else @@ -4044,7 +4023,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c } /* XX using RT clock now, need to initialize value */ -@@ -358,10 +381,10 @@ +@@ -358,10 +381,10 @@ restart: entryno, grub_timeout); else { @@ -4058,7 +4037,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c } grub_timeout--; -@@ -387,12 +410,12 @@ +@@ -387,12 +410,12 @@ restart: if (current_term->flags & TERM_DUMB) grub_putchar ('\r'); else @@ -4073,7 +4052,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c } /* We told them above (at least in SUPPORT_SERIAL) to use -@@ -408,12 +431,12 @@ +@@ -408,12 +431,12 @@ restart: { if (entryno > 0) { @@ -4088,7 +4067,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c get_entry (menu_entries, first_entry + entryno, 0)); -@@ -421,7 +444,7 @@ +@@ -421,7 +444,7 @@ restart: else if (first_entry > 0) { first_entry--; @@ -4097,7 +4076,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c menu_entries); } } -@@ -433,29 +456,29 @@ +@@ -433,29 +456,29 @@ restart: entryno++; else { @@ -4133,7 +4112,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c if (first_entry < 0) { entryno += first_entry; -@@ -463,20 +486,20 @@ +@@ -463,20 +486,20 @@ restart: if (entryno < 0) entryno = 0; } @@ -4158,7 +4137,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c } if (config_entries) -@@ -489,7 +512,7 @@ +@@ -489,7 +512,7 @@ restart: if ((c == 'd') || (c == 'o') || (c == 'O')) { if (! (current_term->flags & TERM_DUMB)) @@ -4167,7 +4146,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c get_entry (menu_entries, first_entry + entryno, 0)); -@@ -537,7 +560,7 @@ +@@ -537,7 +560,7 @@ restart: if (entryno >= num_entries) entryno--; @@ -4176,7 +4155,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c first_entry--; } -@@ -549,7 +572,7 @@ +@@ -549,7 +572,7 @@ restart: grub_printf ("\n"); } else @@ -4185,7 +4164,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c } cur_entry = menu_entries; -@@ -570,7 +593,7 @@ +@@ -570,7 +593,7 @@ restart: if (current_term->flags & TERM_DUMB) grub_printf ("\r "); else @@ -4194,7 +4173,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c /* Wipe out the previously entered password */ grub_memset (entered, 0, sizeof (entered)); -@@ -651,7 +674,10 @@ +@@ -651,7 +674,10 @@ restart: *(new_heap++) = 0; if (config_entries) @@ -4206,7 +4185,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c else { cls (); -@@ -714,6 +740,15 @@ +@@ -714,6 +740,15 @@ restart: cls (); setcursor (1); @@ -4222,7 +4201,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c while (1) { -@@ -727,7 +762,8 @@ +@@ -727,7 +762,8 @@ restart: cur_entry = get_entry (config_entries, first_entry + entryno, 1); /* Set CURRENT_ENTRYNO for the command "savedefault". */ @@ -4232,7 +4211,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c if (run_script (cur_entry, heap)) { -@@ -748,6 +784,13 @@ +@@ -748,6 +784,13 @@ restart: break; } @@ -4246,7 +4225,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c show_menu = 1; goto restart; } -@@ -891,8 +934,18 @@ +@@ -891,8 +934,18 @@ cmain (void) len = grub_read (buf, sizeof (buf)); if (len > 0) { @@ -4266,7 +4245,7 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c } grub_close (); -@@ -1050,6 +1103,16 @@ +@@ -1050,6 +1103,16 @@ cmain (void) while (is_preset); } @@ -4283,10 +4262,9 @@ diff -Naur grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c if (! num_entries) { /* If no acceptable config file, goto command-line, starting -diff -Naur grub-0.97.orig/stage2/term.h grub-0.97/stage2/term.h ---- grub-0.97.orig/stage2/term.h 2003-07-09 04:45:53.000000000 -0700 -+++ grub-0.97/stage2/term.h 2006-07-03 23:58:41.000000000 -0700 -@@ -60,6 +60,8 @@ +--- a/stage2/term.h ++++ b/stage2/term.h +@@ -60,6 +60,8 @@ struct term_entry const char *name; /* The feature flags defined above. */ unsigned long flags; @@ -4295,7 +4273,7 @@ diff -Naur grub-0.97.orig/stage2/term.h grub-0.97/stage2/term.h /* Put a character. */ void (*putchar) (int c); /* Check if any input character is available. */ -@@ -79,6 +81,10 @@ +@@ -79,6 +81,10 @@ struct term_entry void (*setcolor) (int normal_color, int highlight_color); /* Turn on/off the cursor. */ int (*setcursor) (int on); @@ -4306,7 +4284,7 @@ diff -Naur grub-0.97.orig/stage2/term.h grub-0.97/stage2/term.h }; /* This lists up available terminals. */ -@@ -124,4 +130,24 @@ +@@ -124,4 +130,24 @@ void hercules_setcolor (int normal_color int hercules_setcursor (int on); #endif @@ -4331,18 +4309,16 @@ diff -Naur grub-0.97.orig/stage2/term.h grub-0.97/stage2/term.h +#endif /* SUPPORT_GRAPHICS */ + #endif /* ! GRUB_TERM_HEADER */ -diff -Naur grub-0.97.orig/THANKS grub-0.97/THANKS ---- grub-0.97.orig/THANKS 2005-05-07 19:17:43.000000000 -0700 -+++ grub-0.97/THANKS 2006-07-04 00:01:50.000000000 -0700 -@@ -121,3 +121,4 @@ +--- a/THANKS ++++ b/THANKS +@@ -121,3 +121,4 @@ Vesa Jaaskelainen Yury V. Umanets Yuri Zaporogets +Vitaly Fertman -diff -Naur grub-0.97.orig/util/grub-install.in grub-0.97/util/grub-install.in ---- grub-0.97.orig/util/grub-install.in 2004-07-24 11:57:31.000000000 -0700 -+++ grub-0.97/util/grub-install.in 2006-07-04 00:01:50.000000000 -0700 -@@ -81,6 +81,50 @@ +--- a/util/grub-install.in ++++ b/util/grub-install.in +@@ -81,6 +81,50 @@ Report bugs to . EOF } @@ -4393,7 +4369,7 @@ diff -Naur grub-0.97.orig/util/grub-install.in grub-0.97/util/grub-install.in # Usage: convert os_device # Convert an OS device to the corresponding GRUB drive. # This part is OS-specific. -@@ -96,6 +140,10 @@ +@@ -96,6 +140,10 @@ convert () { # Break the device name into the disk part and the partition part. case "$host_os" in linux*) @@ -4404,7 +4380,7 @@ diff -Naur grub-0.97.orig/util/grub-install.in grub-0.97/util/grub-install.in tmp_disk=`echo "$1" | sed -e 's%\([sh]d[a-z]\)[0-9]*$%\1%' \ -e 's%\(d[0-9]*\)p[0-9]*$%\1%' \ -e 's%\(fd[0-9]*\)$%\1%' \ -@@ -112,8 +160,8 @@ +@@ -112,8 +160,8 @@ convert () { tmp_disk=`echo "$1" | sed 's%\([sh]d[0-9]*\).*%\1%'` tmp_part=`echo "$1" | sed "s%$tmp_disk%%"` ;; freebsd* | kfreebsd*-gnu) @@ -4415,7 +4391,7 @@ diff -Naur grub-0.97.orig/util/grub-install.in grub-0.97/util/grub-install.in tmp_part=`echo "$1" \ | sed "s%.*/r\{0,1\}[saw]d[0-9]\(s[0-9]*[a-h]\)%\1%" \ | sed "s%.*/r\{0,1\}da[0-9]\(s[0-9]*[a-h]\)%\1%"` -@@ -131,7 +179,7 @@ +@@ -131,7 +179,7 @@ convert () { # Get the drive name. tmp_drive=`grep -v '^#' $device_map | grep "$tmp_disk *$" \ @@ -4424,7 +4400,7 @@ diff -Naur grub-0.97.orig/util/grub-install.in grub-0.97/util/grub-install.in # If not found, print an error message and exit. if test "x$tmp_drive" = x; then -@@ -148,13 +196,13 @@ +@@ -148,13 +196,13 @@ convert () { gnu*) if echo $tmp_part | grep "^s" >/dev/null; then tmp_pc_slice=`echo $tmp_part \ @@ -4441,7 +4417,7 @@ diff -Naur grub-0.97.orig/util/grub-install.in grub-0.97/util/grub-install.in tmp_drive=`echo "$tmp_drive" \ | sed "s%)%,$tmp_bsd_partition)%"` fi -@@ -336,6 +384,10 @@ +@@ -336,6 +384,10 @@ else # Create a safe temporary file. test -n "$mklog" && log_file=`$mklog` @@ -4452,7 +4428,7 @@ diff -Naur grub-0.97.orig/util/grub-install.in grub-0.97/util/grub-install.in $grub_shell --batch $no_floppy --device-map=$device_map <$log_file quit EOF -@@ -450,6 +502,24 @@ +@@ -450,6 +502,24 @@ rm -f $log_file # Create a safe temporary file. test -n "$mklog" && log_file=`$mklog` @@ -4477,7 +4453,7 @@ diff -Naur grub-0.97.orig/util/grub-install.in grub-0.97/util/grub-install.in # Now perform the installation. $grub_shell --batch $no_floppy --device-map=$device_map <$log_file root $root_drive -@@ -457,6 +527,10 @@ +@@ -457,6 +527,10 @@ setup $force_lba --stage2=$grubdir/stage quit EOF diff --git a/package/hostapd/Makefile b/package/hostapd/Makefile index 5e66f84b0..e6e231386 100644 --- a/package/hostapd/Makefile +++ b/package/hostapd/Makefile @@ -65,9 +65,9 @@ endif ifneq ($(LOCAL_TYPE),hostapd) ifdef CONFIG_WPA_SUPPLICANT_NO_TIMESTAMP_CHECK TARGET_CFLAGS += -DNO_TIMESTAMP_CHECK - DRIVER_MAKEOPTS += \ - CONFIG_DRIVER_ROBOSWITCH=$(CONFIG_PACKAGE_kmod-switch) endif + DRIVER_MAKEOPTS += \ + CONFIG_DRIVER_ROBOSWITCH=$(CONFIG_PACKAGE_kmod-switch) endif define Package/hostapd/Default @@ -75,7 +75,7 @@ define Package/hostapd/Default CATEGORY:=Network TITLE:=IEEE 802.1x Authenticator URL:=http://hostap.epitest.fi/ - DEPENDS:=@!TARGET_avr32 @!TARGET_etrax +PACKAGE_kmod-mac80211:libnl-tiny + DEPENDS:=@!TARGET_avr32 @!TARGET_etrax +PACKAGE_kmod-mac80211:libnl-tiny +PACKAGE_kmod-mac80211:crda MAINTAINER:=Felix Fietkau endef @@ -116,7 +116,7 @@ define Package/wpad/Default CATEGORY:=Network TITLE:=IEEE 802.1x Authenticator/Supplicant URL:=http://hostap.epitest.fi/ - DEPENDS:=@!TARGET_avr32 @!TARGET_etrax +PACKAGE_kmod-mac80211:libnl-tiny + DEPENDS:=@!TARGET_avr32 @!TARGET_etrax +PACKAGE_kmod-mac80211:libnl-tiny +PACKAGE_kmod-mac80211:crda MAINTAINER:=Felix Fietkau endef @@ -146,7 +146,7 @@ define Package/wpa-supplicant CATEGORY:=Network TITLE:=WPA Supplicant URL:=http://hostap.epitest.fi/wpa_supplicant/ - DEPENDS:=@!TARGET_avr32 @!TARGET_etrax +PACKAGE_kmod-mac80211:libnl-tiny + DEPENDS:=@!TARGET_avr32 @!TARGET_etrax +PACKAGE_kmod-mac80211:libnl-tiny +PACKAGE_kmod-mac80211:crda VARIANT:=supplicant-full MAINTAINER:=Felix Fietkau endef @@ -224,7 +224,8 @@ endef define Build/Compile/wpad echo ` \ $(call Build/RunMake,hostapd,-s MULTICALL=1 dump_cflags); \ - $(call Build/RunMake,wpa_supplicant,-s dump_cflags) | sed -e 's,$(TARGET_CFLAGS),,' \ + $(call Build/RunMake,wpa_supplicant,-s dump_cflags) | \ + sed -e 's,-n ,,g' -e 's,$(TARGET_CFLAGS),,' \ ` > $(PKG_BUILD_DIR)/.cflags $(call Build/RunMake,hostapd, \ CFLAGS="$$$$(cat $(PKG_BUILD_DIR)/.cflags)" \ diff --git a/package/hostapd/files/hostapd.sh b/package/hostapd/files/hostapd.sh index 9ee7657e2..b477cd773 100644 --- a/package/hostapd/files/hostapd.sh +++ b/package/hostapd/files/hostapd.sh @@ -68,6 +68,28 @@ hostapd_set_bss_options() { append "$var" "wpa_group_rekey=300" "$N" append "$var" "wpa_gmk_rekey=640" "$N" ;; + *wep*) + config_get key "$vif" key + key="${key:-1}" + case "$key" in + [1234]) + for idx in 1 2 3 4; do + local zidx + zidx=$(($idx - 1)) + config_get ckey "$vif" "key${idx}" + [ -n "$ckey" ] && \ + append "$var" "wep_key${zidx}=$(prepare_key_wep "$ckey")" "$N" + done + append "$var" "wep_default_key=$((key - 1))" "$N" + ;; + *) + append "$var" "wep_key0=$(prepare_key_wep "$key")" "$N" + append "$var" "wep_default_key=0" "$N" + ;; + esac + wpa=0 + crypto= + ;; *) wpa=0 crypto= diff --git a/package/hostapd/files/wpa_supplicant.sh b/package/hostapd/files/wpa_supplicant.sh index ccf31baa9..97a00829d 100644 --- a/package/hostapd/files/wpa_supplicant.sh +++ b/package/hostapd/files/wpa_supplicant.sh @@ -6,7 +6,10 @@ wpa_supplicant_setup_vif() { # wpa_supplicant should use wext for mac80211 cards [ "$driver" = "mac80211" ] && driver='wext' - # make sure we have the psk + # make sure we have the encryption type and the psk + [ -n "$enc" ] || { + config_get enc "$vif" encryption + } [ -n "$key" ] || { config_get key "$vif" key } diff --git a/package/iproute2/Makefile b/package/iproute2/Makefile index a3b5f471c..c7c3e2be5 100644 --- a/package/iproute2/Makefile +++ b/package/iproute2/Makefile @@ -33,6 +33,7 @@ endef define Package/tc $(call Package/iproute2/Default) TITLE:=Traffic control utility + DEPENDS:=+kmod-sched endef define Package/genl diff --git a/package/iptables/Makefile b/package/iptables/Makefile index 375f453e4..68ccc7628 100644 --- a/package/iptables/Makefile +++ b/package/iptables/Makefile @@ -68,6 +68,8 @@ define Package/iptables-mod-conntrack/description Basic iptables extensions for connection tracking. Includes: - state + - raw + - NOTRACK endef define Package/iptables-mod-conntrack-extra @@ -210,8 +212,6 @@ define Package/iptables-mod-extra/description - libipt_physdev - libipt_pkttype - libipt_recent - - iptable_raw - - libipt_NOTRACK endef define Package/iptables-utils @@ -254,6 +254,10 @@ TARGET_CPPFLAGS := \ -I$(LINUX_DIR)/arch/$(LINUX_KARCH)/include \ $(TARGET_CPPFLAGS) +TARGET_CFLAGS := \ + $(TARGET_CFLAGS) \ + -DFORCE_MODPROBE_PROGRAM="\\\"/sbin/insmod\\\"" + CONFIGURE_ARGS += \ --enable-shared \ --enable-devel \ diff --git a/package/iptables/patches/010-multiport-linux-2.4-compat.patch b/package/iptables/patches/010-multiport-linux-2.4-compat.patch new file mode 100644 index 000000000..7233d3aeb --- /dev/null +++ b/package/iptables/patches/010-multiport-linux-2.4-compat.patch @@ -0,0 +1,265 @@ +--- a/extensions/libxt_multiport.c ++++ b/extensions/libxt_multiport.c +@@ -14,21 +14,6 @@ + #include + + /* Function which prints out usage message. */ +-static void multiport_help(void) +-{ +- printf( +-"multiport match options:\n" +-" --source-ports port[,port,port...]\n" +-" --sports ...\n" +-" match source port(s)\n" +-" --destination-ports port[,port,port...]\n" +-" --dports ...\n" +-" match destination port(s)\n" +-" --ports port[,port,port]\n" +-" match both source and destination port(s)\n" +-" NOTE: this kernel does not support port ranges in multiport.\n"); +-} +- + static void multiport_help_v1(void) + { + printf( +@@ -71,26 +56,6 @@ + } + } + +-static unsigned int +-parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto) +-{ +- char *buffer, *cp, *next; +- unsigned int i; +- +- buffer = strdup(portstring); +- if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed"); +- +- for (cp=buffer, i=0; cp && idata; +- +- switch (c) { +- case '1': +- xtables_check_inverse(optarg, &invert, &optind, 0, argv); +- proto = check_proto(pnum, invflags); +- multiinfo->count = parse_multi_ports(optarg, +- multiinfo->ports, proto); +- multiinfo->flags = XT_MULTIPORT_SOURCE; +- break; +- +- case '2': +- xtables_check_inverse(optarg, &invert, &optind, 0, argv); +- proto = check_proto(pnum, invflags); +- multiinfo->count = parse_multi_ports(optarg, +- multiinfo->ports, proto); +- multiinfo->flags = XT_MULTIPORT_DESTINATION; +- break; +- +- case '3': +- xtables_check_inverse(optarg, &invert, &optind, 0, argv); +- proto = check_proto(pnum, invflags); +- multiinfo->count = parse_multi_ports(optarg, +- multiinfo->ports, proto); +- multiinfo->flags = XT_MULTIPORT_EITHER; +- break; +- +- default: +- return 0; +- } +- +- if (invert) +- xtables_error(PARAMETER_PROBLEM, +- "multiport does not support invert"); +- +- if (*flags) +- xtables_error(PARAMETER_PROBLEM, +- "multiport can only have one option"); +- *flags = 1; +- return 1; +-} +- +-static int +-multiport_parse(int c, char **argv, int invert, unsigned int *flags, +- const void *e, struct xt_entry_match **match) +-{ +- const struct ipt_entry *entry = e; +- return __multiport_parse(c, argv, invert, flags, match, +- entry->ip.proto, entry->ip.invflags); +-} +- +-static int +-multiport_parse6(int c, char **argv, int invert, unsigned int *flags, +- const void *e, struct xt_entry_match **match) +-{ +- const struct ip6t_entry *entry = e; +- return __multiport_parse(c, argv, invert, flags, match, +- entry->ipv6.proto, entry->ipv6.invflags); +-} +- +-static int + __multiport_parse_v1(int c, char **argv, int invert, unsigned int *flags, + struct xt_entry_match **match, u_int16_t pnum, + u_int8_t invflags) +@@ -313,55 +211,6 @@ + } + + /* Prints out the matchinfo. */ +-static void +-__multiport_print(const struct xt_entry_match *match, int numeric, +- u_int16_t proto) +-{ +- const struct xt_multiport *multiinfo +- = (const struct xt_multiport *)match->data; +- unsigned int i; +- +- printf("multiport "); +- +- switch (multiinfo->flags) { +- case XT_MULTIPORT_SOURCE: +- printf("sports "); +- break; +- +- case XT_MULTIPORT_DESTINATION: +- printf("dports "); +- break; +- +- case XT_MULTIPORT_EITHER: +- printf("ports "); +- break; +- +- default: +- printf("ERROR "); +- break; +- } +- +- for (i=0; i < multiinfo->count; i++) { +- printf("%s", i ? "," : ""); +- print_port(multiinfo->ports[i], proto, numeric); +- } +- printf(" "); +-} +- +-static void multiport_print(const void *ip_void, +- const struct xt_entry_match *match, int numeric) +-{ +- const struct ipt_ip *ip = ip_void; +- __multiport_print(match, numeric, ip->proto); +-} +- +-static void multiport_print6(const void *ip_void, +- const struct xt_entry_match *match, int numeric) +-{ +- const struct ip6t_ip6 *ip = ip_void; +- __multiport_print(match, numeric, ip->proto); +-} +- + static void __multiport_print_v1(const struct xt_entry_match *match, + int numeric, u_int16_t proto) + { +@@ -418,48 +267,6 @@ + } + + /* Saves the union ipt_matchinfo in parsable form to stdout. */ +-static void __multiport_save(const struct xt_entry_match *match, +- u_int16_t proto) +-{ +- const struct xt_multiport *multiinfo +- = (const struct xt_multiport *)match->data; +- unsigned int i; +- +- switch (multiinfo->flags) { +- case XT_MULTIPORT_SOURCE: +- printf("--sports "); +- break; +- +- case XT_MULTIPORT_DESTINATION: +- printf("--dports "); +- break; +- +- case XT_MULTIPORT_EITHER: +- printf("--ports "); +- break; +- } +- +- for (i=0; i < multiinfo->count; i++) { +- printf("%s", i ? "," : ""); +- print_port(multiinfo->ports[i], proto, 1); +- } +- printf(" "); +-} +- +-static void multiport_save(const void *ip_void, +- const struct xt_entry_match *match) +-{ +- const struct ipt_ip *ip = ip_void; +- __multiport_save(match, ip->proto); +-} +- +-static void multiport_save6(const void *ip_void, +- const struct xt_entry_match *match) +-{ +- const struct ip6t_ip6 *ip = ip_void; +- __multiport_save(match, ip->proto); +-} +- + static void __multiport_save_v1(const struct xt_entry_match *match, + u_int16_t proto) + { +@@ -513,34 +320,6 @@ + { + .family = NFPROTO_IPV4, + .name = "multiport", +- .revision = 0, +- .version = XTABLES_VERSION, +- .size = XT_ALIGN(sizeof(struct xt_multiport)), +- .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)), +- .help = multiport_help, +- .parse = multiport_parse, +- .final_check = multiport_check, +- .print = multiport_print, +- .save = multiport_save, +- .extra_opts = multiport_opts, +- }, +- { +- .family = NFPROTO_IPV6, +- .name = "multiport", +- .revision = 0, +- .version = XTABLES_VERSION, +- .size = XT_ALIGN(sizeof(struct xt_multiport)), +- .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)), +- .help = multiport_help, +- .parse = multiport_parse6, +- .final_check = multiport_check, +- .print = multiport_print6, +- .save = multiport_save6, +- .extra_opts = multiport_opts, +- }, +- { +- .family = NFPROTO_IPV4, +- .name = "multiport", + .version = XTABLES_VERSION, + .revision = 1, + .size = XT_ALIGN(sizeof(struct xt_multiport_v1)), diff --git a/package/iptables/patches/020-iptables-force-modprobe-util.patch b/package/iptables/patches/020-iptables-force-modprobe-util.patch new file mode 100644 index 000000000..32c9fcd51 --- /dev/null +++ b/package/iptables/patches/020-iptables-force-modprobe-util.patch @@ -0,0 +1,20 @@ +--- a/xtables.c ++++ b/xtables.c +@@ -285,6 +285,7 @@ void *xtables_realloc(void *ptr, size_t + + static char *get_modprobe(void) + { ++#ifndef FORCE_MODPROBE_PROGRAM + int procfile; + char *ret; + +@@ -309,6 +310,9 @@ static char *get_modprobe(void) + free(ret); + close(procfile); + return NULL; ++#else ++ return strdup(FORCE_MODPROBE_PROGRAM); ++#endif + } + + int xtables_insmod(const char *modname, const char *modprobe, bool quiet) diff --git a/package/kernel/modules/block.mk b/package/kernel/modules/block.mk index 34c6f9927..c6d389491 100644 --- a/package/kernel/modules/block.mk +++ b/package/kernel/modules/block.mk @@ -39,6 +39,20 @@ endef $(eval $(call KernelPackage,ata-ahci)) +define KernelPackage/ata-sil +$(call KernelPackage/ata/Depends,) + TITLE:=Silicon Image SATA support + KCONFIG:=CONFIG_SATA_SIL + FILES:=$(LINUX_DIR)/drivers/ata/sata_sil.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,41,sata_sil) +endef + +define KernelPackage/ata-sil/description + Support for Silicon Image Serial ATA controllers. +endef + +$(eval $(call KernelPackage,ata-sil)) + define KernelPackage/ata-sil24 $(call KernelPackage/ata/Depends,) @@ -307,7 +321,7 @@ define KernelPackage/scsi-core CONFIG_SCSI \ CONFIG_BLK_DEV_SD FILES:= \ - $(LINUX_DIR)/drivers/scsi/scsi_mod.$(LINUX_KMOD_SUFFIX) \ + $(if $(findstring y,$(CONFIG_SCSI)),,$(LINUX_DIR)/drivers/scsi/scsi_mod.$(LINUX_KMOD_SUFFIX)) \ $(LINUX_DIR)/drivers/scsi/sd_mod.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,20,scsi_mod) $(call AutoLoad,40,sd_mod) endef @@ -375,6 +389,7 @@ define KernelPackage/dm CONFIG_DM_MULTIPATH=n \ CONFIG_DM_ZERO=n \ CONFIG_DM_SNAPSHOT=n \ + CONFIG_DM_LOG_USERSPACE=n \ CONFIG_MD=y \ CONFIG_BLK_DEV_DM \ CONFIG_DM_MIRROR diff --git a/package/kernel/modules/fs.mk b/package/kernel/modules/fs.mk index fc1bd17d0..9e2db605b 100644 --- a/package/kernel/modules/fs.mk +++ b/package/kernel/modules/fs.mk @@ -61,7 +61,7 @@ $(eval $(call KernelPackage,fs-ntfs)) define KernelPackage/fs-mbcache SUBMENU:=$(FS_MENU) - TITLE:=mbcache (used by ext2/ext3) + TITLE:=mbcache (used by ext2/ext3/ext4) KCONFIG:=CONFIG_FS_MBCACHE ifneq ($(CONFIG_FS_MBCACHE),) FILES:=$(LINUX_DIR)/fs/mbcache.$(LINUX_KMOD_SUFFIX) @@ -115,7 +115,6 @@ define KernelPackage/fs-ext4 SUBMENU:=$(FS_MENU) TITLE:=EXT4 filesystem support KCONFIG:= \ - CONFIG_EXT4DEV_COMPAT=y \ CONFIG_EXT4_FS_XATTR=y \ CONFIG_EXT4_FS_POSIX_ACL=y \ CONFIG_EXT4_FS_SECURITY=y \ @@ -125,7 +124,7 @@ define KernelPackage/fs-ext4 FILES:= \ $(LINUX_DIR)/fs/ext4/ext4.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/fs/jbd2/jbd2.$(LINUX_KMOD_SUFFIX) - AUTOLOAD:=$(call AutoLoad,30,jbd2 $(EXT4_NAME)) + AUTOLOAD:=$(call AutoLoad,30,jbd2 ext4) endef define KernelPackage/fs-ext4/description @@ -214,13 +213,26 @@ define KernelPackage/fs-nfs-common AUTOLOAD:=$(call AutoLoad,30,sunrpc lockd) endef -define KernelPackage/fs-nfs-common/2.6 - KCONFIG+=CONFIG_SUNRPC_GSS +$(eval $(call KernelPackage,fs-nfs-common)) + + +define KernelPackage/fs-nfs-common-v4 + SUBMENU:=$(FS_MENU) + TITLE:=Common NFS V4 filesystem modules + KCONFIG+=\ + CONFIG_SUNRPC_GSS\ + CONFIG_NFS_V4=y\ + CONFIG_NFSD_V4=y + DEPENDS:= @LINUX_2_6 +kmod-fs-nfs-common FILES+=$(LINUX_DIR)/net/sunrpc/auth_gss/auth_rpcgss.$(LINUX_KMOD_SUFFIX) - AUTOLOAD=$(call AutoLoad,30,sunrpc lockd auth_rpcgss) + AUTOLOAD=$(call AutoLoad,30,auth_rpcgss) endef -$(eval $(call KernelPackage,fs-nfs-common)) +define KernelPackage/fs-nfs-common-v4/description + Kernel modules for NFS V4 & NFSD V4 kernel support +endef + +$(eval $(call KernelPackage,fs-nfs-common-v4)) define KernelPackage/fs-nfs diff --git a/package/kernel/modules/netsupport.mk b/package/kernel/modules/netsupport.mk index 9e9cdcbb6..16a8378ad 100644 --- a/package/kernel/modules/netsupport.mk +++ b/package/kernel/modules/netsupport.mk @@ -568,6 +568,7 @@ define KernelPackage/sched CONFIG_NET_SCH_INGRESS \ CONFIG_NET_SCH_PRIO \ CONFIG_NET_SCH_RED \ + CONFIG_NET_SCH_TBF \ CONFIG_NET_SCH_SFQ \ CONFIG_NET_SCH_TEQL \ CONFIG_NET_CLS=y \ diff --git a/package/kernel/modules/other.mk b/package/kernel/modules/other.mk index 47fee9f53..ada8365a7 100644 --- a/package/kernel/modules/other.mk +++ b/package/kernel/modules/other.mk @@ -7,6 +7,14 @@ OTHER_MENU:=Other modules +define KernelPackage/block2mtd + SUBMENU:=$(OTHER_MENU) + TITLE:=Block device MTD emulation + KCONFIG:=CONFIG_MTD_BLOCK2MTD + FILES:=$(LINUX_DIR)/drivers/mtd/devices/block2mtd.$(LINUX_KMOD_SUFFIX) +endef +$(eval $(call KernelPackage,block2mtd)) + define KernelPackage/crc-itu-t SUBMENU:=$(OTHER_MENU) TITLE:=CRC ITU-T V.41 support diff --git a/package/kernel/modules/usb.mk b/package/kernel/modules/usb.mk index 12e9effe7..a8b2739c0 100644 --- a/package/kernel/modules/usb.mk +++ b/package/kernel/modules/usb.mk @@ -360,19 +360,19 @@ endef $(eval $(call KernelPackage,usb-serial-pl2303)) -define KernelPackage/usb-serial-cp2101 +define KernelPackage/usb-serial-cp210x $(call KernelPackage/usb-serial/Depends,) - TITLE:=Support for Silicon Labs cp2101 devices - KCONFIG:=CONFIG_USB_SERIAL_CP2101 - FILES:=$(LINUX_DIR)/drivers/usb/serial/cp2101.$(LINUX_KMOD_SUFFIX) - AUTOLOAD:=$(call AutoLoad,65,cp2101) + TITLE:=Support for Silicon Labs cp210x devices + KCONFIG:=CONFIG_USB_SERIAL_CP210X + FILES:=$(LINUX_DIR)/drivers/usb/serial/cp210x.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,65,cp210x) endef -define KernelPackage/usb-serial-cp2101/description - Kernel support for Silicon Labs cp2101 USB-to-Serial converters +define KernelPackage/usb-serial-cp210x/description + Kernel support for Silicon Labs cp210x USB-to-Serial converters endef -$(eval $(call KernelPackage,usb-serial-cp2101)) +$(eval $(call KernelPackage,usb-serial-cp210x)) define KernelPackage/usb-serial-ark3116 diff --git a/package/linux-atm/Makefile b/package/linux-atm/Makefile index 330f56bb5..551443b33 100644 --- a/package/linux-atm/Makefile +++ b/package/linux-atm/Makefile @@ -1,4 +1,4 @@ -# +# # Copyright (C) 2006 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. @@ -15,12 +15,15 @@ PKG_SOURCE:=$(PKG_NAME)_$(PKG_VERSION).orig.tar.gz PKG_SOURCE_URL:=http://ftp.debian.org/debian/pool/main/l/linux-atm/ PKG_MD5SUM:=84fef49cc39ff2605204246666f65864 +PKG_FIXUP:=libtool + include $(INCLUDE_DIR)/package.mk define Package/linux-atm SECTION:=libs CATEGORY:=Libraries TITLE:=Linux ATM library + DEPENDS:=+kmod-atm URL:=http://linux-atm.sourceforge.net/ endef diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile index a9c868763..81733d772 100644 --- a/package/mac80211/Makefile +++ b/package/mac80211/Makefile @@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mac80211 -PKG_VERSION:=2010-02-02 -PKG_RELEASE:=2 +PKG_VERSION:=2010-02-16 +PKG_RELEASE:=3 PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources # http://www.orbit-lab.org/kernel/compat-wireless-2.6/2010/11 \ # http://wireless.kernel.org/download/compat-wireless-2.6 -PKG_MD5SUM:=32602171b840132cbaa62d4b67f32d2c +PKG_MD5SUM:=190060a705c2b78e9b0bc873a8803b37 PKG_SOURCE:=compat-wireless-$(PKG_VERSION).tar.bz2 PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION) @@ -182,7 +182,7 @@ endef define KernelPackage/rt2800-lib $(call KernelPackage/rt2x00/Default) - DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT) +kmod-rt2x00-lib + DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT) +kmod-rt2x00-lib +USB_SUPPORT:kmod-rt2x00-usb TITLE+= (rt2800 LIB) FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2800lib.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,27,rt2800lib) diff --git a/package/mac80211/files/lib/wifi/mac80211.sh b/package/mac80211/files/lib/wifi/mac80211.sh index 27e234d83..257277a28 100644 --- a/package/mac80211/files/lib/wifi/mac80211.sh +++ b/package/mac80211/files/lib/wifi/mac80211.sh @@ -234,7 +234,6 @@ enable_mac80211() { } config_set "$vif" ifname "$ifname" - config_get enc "$vif" encryption config_get mode "$vif" mode config_get ssid "$vif" ssid @@ -288,60 +287,19 @@ enable_mac80211() { [ "$mode" = "ap" ] || ifconfig "$ifname" hw ether "$vif_mac" config_set "$vif" macaddr "$vif_mac" - # Valid values are: - # wpa / wep / none - # # !! ap !! # # ALL ap functionality will be passed to hostapd # - # !! mesh / adhoc / station !! - # none -> NO encryption + # !! station !! # - # wep + keymgmt = '' -> we use iw to connect to the - # network. + # ALL station functionality will be passed to wpa_supplicant # - # wep + keymgmt = 'NONE' -> wpa_supplicant will be - # configured to handle the wep connection if [ ! "$mode" = "ap" ]; then # We attempt to set the channel for all interfaces, although # mac80211 may not support it or the driver might not yet # for ap mode this is handled by hostapd [ -n "$fixed" -a -n "$channel" ] && iw dev "$ifname" set channel "$channel" - - local key keystring - - case "$enc" in - *none*) - config_get keymgmt "$vif" keymgmt - ;; - *wep*) - config_get keymgmt "$vif" keymgmt - if [ -z "$keymgmt" ]; then - config_get key "$vif" key - key="${key:-1}" - case "$key" in - [1234]) - for idx in 1 2 3 4; do - local zidx - zidx=$(($idx - 1)) - config_get ckey "$vif" "key${idx}" - if [ -n "$ckey" ]; then - [ $idx -eq $key ] && zidx="d:${zidx}" - append keystring "${zidx}:$(prepare_key_wep "$ckey")" - fi - done - ;; - *) - keystring="d:0:$(prepare_key_wep "$key")" - ;; - esac - fi - ;; - *psk*|*wpa*) - config_get key "$vif" key - ;; - esac fi # txpower is not yet implemented in iw @@ -363,60 +321,26 @@ enable_mac80211() { ifconfig "$ifname" up - [ "$mode" = "ap" ] || mac80211_start_vif "$vif" "$ifname" + if [ ! "$mode" = "ap" ]; then + mac80211_start_vif "$vif" "$ifname" - case "$mode" in - adhoc) - config_get bssid "$vif" bssid - iw dev "$ifname" ibss join "$ssid" $freq ${fixed:+fixed-freq} $bssid - ;; - sta|mesh) - config_get bssid "$vif" bssid - case "$enc" in - *wep*) - if [ -z "$keymgmt" ]; then - [ -n "$keystring" ] && - iw dev "$ifname" connect "$ssid" ${fixed:+$freq} $bssid key $keystring - else - if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then - wpa_supplicant_setup_vif "$vif" wext || { - echo "enable_mac80211($device): Failed to set up wpa_supplicant for interface $ifname" >&2 - # make sure this wifi interface won't accidentally stay open without encryption - ifconfig "$ifname" down - continue - } - fi - fi - ;; - *wpa*|*psk*) - config_get key "$vif" key - if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then - wpa_supplicant_setup_vif "$vif" wext || { - echo "enable_mac80211($device): Failed to set up wpa_supplicant for interface $ifname" >&2 - # make sure this wifi interface won't accidentally stay open without encryption - ifconfig "$ifname" down - continue - } - fi - ;; - *) - if [ -z "$keymgmt" ]; then - iw dev "$ifname" connect "$ssid" ${fixed:+$freq} $bssid - else - if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then - wpa_supplicant_setup_vif "$vif" wext || { - echo "enable_mac80211($device): Failed to set up wpa_supplicant for interface $ifname" >&2 - # make sure this wifi interface won't accidentally stay open without encryption - ifconfig "$ifname" down - continue - } - fi - fi - ;; - esac - - ;; - esac + case "$mode" in + adhoc) + config_get bssid "$vif" bssid + iw dev "$ifname" ibss join "$ssid" $freq ${fixed:+fixed-freq} $bssid + ;; + sta) + if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then + wpa_supplicant_setup_vif "$vif" wext || { + echo "enable_mac80211($device): Failed to set up wpa_supplicant for interface $ifname" >&2 + # make sure this wifi interface won't accidentally stay open without encryption + ifconfig "$ifname" down + continue + } + fi + ;; + esac + fi done local start_hostapd= diff --git a/package/mac80211/patches/001-disable_b44.patch b/package/mac80211/patches/001-disable_b44.patch index e15d94e1c..0682e746c 100644 --- a/package/mac80211/patches/001-disable_b44.patch +++ b/package/mac80211/patches/001-disable_b44.patch @@ -1,16 +1,12 @@ --- a/config.mk +++ b/config.mk -@@ -283,10 +283,10 @@ endif +@@ -271,8 +271,8 @@ endif CONFIG_P54_PCI=m -CONFIG_B44=m --CONFIG_B44_PCI_AUTOSELECT=y --CONFIG_B44_PCICORE_AUTOSELECT=y -CONFIG_B44_PCI=y +# CONFIG_B44=m -+# CONFIG_B44_PCI_AUTOSELECT=y -+# CONFIG_B44_PCICORE_AUTOSELECT=y +# CONFIG_B44_PCI=y CONFIG_RTL8180=m diff --git a/package/mac80211/patches/002-disable_rfkill.patch b/package/mac80211/patches/002-disable_rfkill.patch index fcee2fea9..17fd787dd 100644 --- a/package/mac80211/patches/002-disable_rfkill.patch +++ b/package/mac80211/patches/002-disable_rfkill.patch @@ -1,6 +1,6 @@ --- a/config.mk +++ b/config.mk -@@ -73,7 +73,7 @@ endif # build check +@@ -72,7 +72,7 @@ endif # build check endif # kernel Makefile check # These both are needed by compat-wireless || compat-bluetooth so enable them @@ -9,7 +9,7 @@ ifeq ($(CONFIG_MAC80211),y) $(error "ERROR: you have MAC80211 compiled into the kernel, CONFIG_MAC80211=y, as such you cannot replace its mac80211 driver. You need this set to CONFIG_MAC80211=m. If you are using Fedora upgrade your kernel as later version should this set as modular. For further information on Fedora see https://bugzilla.redhat.com/show_bug.cgi?id=470143. If you are using your own kernel recompile it and make mac80211 modular") -@@ -476,8 +476,8 @@ endif +@@ -461,8 +461,8 @@ endif # We need the backported rfkill module on kernel < 2.6.31. # In more recent kernel versions use the in kernel rfkill module. ifdef CONFIG_COMPAT_KERNEL_31 diff --git a/package/mac80211/patches/003-disable_bt.patch b/package/mac80211/patches/003-disable_bt.patch index 147450da7..e1e7443ab 100644 --- a/package/mac80211/patches/003-disable_bt.patch +++ b/package/mac80211/patches/003-disable_bt.patch @@ -1,6 +1,6 @@ --- a/config.mk +++ b/config.mk -@@ -95,8 +95,8 @@ ifndef CONFIG_COMPAT_KERNEL_27 +@@ -94,8 +94,8 @@ ifndef CONFIG_COMPAT_KERNEL_27 ifeq ($(CONFIG_BT),y) # we'll ignore compiling bluetooth else diff --git a/package/mac80211/patches/007-remove_misc_drivers.patch b/package/mac80211/patches/007-remove_misc_drivers.patch index 413fdd063..c648b8651 100644 --- a/package/mac80211/patches/007-remove_misc_drivers.patch +++ b/package/mac80211/patches/007-remove_misc_drivers.patch @@ -1,6 +1,6 @@ --- a/config.mk +++ b/config.mk -@@ -316,10 +316,10 @@ CONFIG_PCI_ATMEL=m +@@ -296,10 +296,10 @@ endif CONFIG_MWL8K=m # Ethernet drivers go here @@ -15,7 +15,7 @@ endif ## end of PCI -@@ -358,10 +358,10 @@ CONFIG_USB_NET_COMPAT_RNDIS_HOST=n +@@ -338,10 +338,10 @@ CONFIG_USB_NET_COMPAT_RNDIS_HOST=n CONFIG_USB_NET_COMPAT_RNDIS_WLAN=n CONFIG_USB_NET_COMPAT_CDCETHER=n else diff --git a/package/mac80211/patches/009-remove_mac80211_module_dependence.patch b/package/mac80211/patches/009-remove_mac80211_module_dependence.patch index 68420d8a2..1043be978 100644 --- a/package/mac80211/patches/009-remove_mac80211_module_dependence.patch +++ b/package/mac80211/patches/009-remove_mac80211_module_dependence.patch @@ -1,6 +1,6 @@ --- a/config.mk +++ b/config.mk -@@ -44,21 +44,6 @@ $(error "ERROR: Your 2.6.27 kernel has C +@@ -43,21 +43,6 @@ $(error "ERROR: Your 2.6.27 kernel has C endif endif diff --git a/package/mac80211/patches/010-b43_config.patch b/package/mac80211/patches/010-b43_config.patch deleted file mode 100644 index 6a9738ef0..000000000 --- a/package/mac80211/patches/010-b43_config.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- a/config.mk -+++ b/config.mk -@@ -201,9 +201,9 @@ CONFIG_B43_HWRNG=y - CONFIG_B43_PCI_AUTOSELECT=y - CONFIG_B43_PCICORE_AUTOSELECT=y - ifneq ($(CONFIG_PCMCIA),) --CONFIG_B43_PCMCIA=y -+# CONFIG_B43_PCMCIA=y - endif --CONFIG_B43_PIO=y -+# CONFIG_B43_PIO=y - CONFIG_B43_LEDS=y - CONFIG_B43_PHY_LP=y - # CONFIG_B43_DEBUG=y -@@ -258,8 +258,8 @@ CONFIG_SSB_PCIHOST_POSSIBLE=y - CONFIG_SSB_PCIHOST=y - CONFIG_SSB_B43_PCI_BRIDGE=y - ifneq ($(CONFIG_PCMCIA),) --CONFIG_SSB_PCMCIAHOST_POSSIBLE=y --CONFIG_SSB_PCMCIAHOST=y -+# CONFIG_SSB_PCMCIAHOST_POSSIBLE=y -+# CONFIG_SSB_PCMCIAHOST=y - endif - # CONFIG_SSB_DEBUG=y - CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y diff --git a/package/mac80211/patches/010-no_pcmcia.patch b/package/mac80211/patches/010-no_pcmcia.patch new file mode 100644 index 000000000..1334dbb14 --- /dev/null +++ b/package/mac80211/patches/010-no_pcmcia.patch @@ -0,0 +1,29 @@ +--- a/config.mk ++++ b/config.mk +@@ -8,7 +8,7 @@ ifeq ($(wildcard $(KLIB_BUILD)/.config), + # These will be ignored by compat autoconf + CONFIG_PCI=y + CONFIG_USB=y +- CONFIG_PCMCIA=y ++# CONFIG_PCMCIA=y + CONFIG_SSB=m + else + include $(KLIB_BUILD)/.config +@@ -197,7 +197,7 @@ CONFIG_B43=m + CONFIG_B43_HWRNG=y + CONFIG_B43_PCI_AUTOSELECT=y + ifneq ($(CONFIG_PCMCIA),) +-CONFIG_B43_PCMCIA=y ++# CONFIG_B43_PCMCIA=y + endif + CONFIG_B43_LEDS=y + CONFIG_B43_PHY_LP=y +@@ -248,7 +248,7 @@ CONFIG_SSB_BLOCKIO=y + CONFIG_SSB_PCIHOST=y + CONFIG_SSB_B43_PCI_BRIDGE=y + ifneq ($(CONFIG_PCMCIA),) +-CONFIG_SSB_PCMCIAHOST=y ++# CONFIG_SSB_PCMCIAHOST=y + endif + # CONFIG_SSB_DEBUG=y + CONFIG_SSB_DRIVER_PCICORE=y diff --git a/package/mac80211/patches/011-no_sdio.patch b/package/mac80211/patches/011-no_sdio.patch new file mode 100644 index 000000000..aa651edd2 --- /dev/null +++ b/package/mac80211/patches/011-no_sdio.patch @@ -0,0 +1,13 @@ +--- a/config.mk ++++ b/config.mk +@@ -382,8 +382,8 @@ endif # end of SPI driver list + + ifneq ($(CONFIG_MMC),) + +-CONFIG_SSB_SDIOHOST=y +-CONFIG_B43_SDIO=y ++# CONFIG_SSB_SDIOHOST=y ++# CONFIG_B43_SDIO=y + CONFIG_WL1251_SDIO=m + + ifdef CONFIG_COMPAT_KERNEL_27 diff --git a/package/mac80211/patches/120-linux-2.6.30-compat.patch b/package/mac80211/patches/120-linux-2.6.30-compat.patch new file mode 100644 index 000000000..da5966e15 --- /dev/null +++ b/package/mac80211/patches/120-linux-2.6.30-compat.patch @@ -0,0 +1,14 @@ +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -5662,7 +5662,11 @@ int nl80211_send_action(struct cfg80211_ + return err; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)) + err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); ++#else ++ err = genlmsg_unicast(msg, nlpid); ++#endif + if (err < 0) + return err; + return 0; diff --git a/package/mac80211/patches/404-ath_regd_optional.patch b/package/mac80211/patches/404-ath_regd_optional.patch index a5413697b..58ed4bdbe 100644 --- a/package/mac80211/patches/404-ath_regd_optional.patch +++ b/package/mac80211/patches/404-ath_regd_optional.patch @@ -10,7 +10,7 @@ #include "regd_common.h" /* -@@ -587,3 +590,5 @@ u32 ath_regd_get_band_ctl(struct ath_reg +@@ -588,3 +591,5 @@ u32 ath_regd_get_band_ctl(struct ath_reg } } EXPORT_SYMBOL(ath_regd_get_band_ctl); diff --git a/package/mac80211/patches/408-ath9k_tweak_rx_intr_mitigation.patch b/package/mac80211/patches/408-ath9k_tweak_rx_intr_mitigation.patch index 949a9a7e2..1c85205d8 100644 --- a/package/mac80211/patches/408-ath9k_tweak_rx_intr_mitigation.patch +++ b/package/mac80211/patches/408-ath9k_tweak_rx_intr_mitigation.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c -@@ -2092,7 +2092,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st +@@ -2103,7 +2103,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st if (ah->config.rx_intr_mitigation) { REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); diff --git a/package/mac80211/patches/409-ath9k-add-wndr3700-antenna-initialization.patch b/package/mac80211/patches/409-ath9k-add-wndr3700-antenna-initialization.patch index 98c989176..83eabaf09 100644 --- a/package/mac80211/patches/409-ath9k-add-wndr3700-antenna-initialization.patch +++ b/package/mac80211/patches/409-ath9k-add-wndr3700-antenna-initialization.patch @@ -17,7 +17,7 @@ common = ath9k_hw_common(ah); common->ops = &ath9k_common_ops; -@@ -670,6 +673,24 @@ void ath9k_set_hw_capab(struct ath_softc +@@ -671,6 +674,24 @@ void ath9k_set_hw_capab(struct ath_softc SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } @@ -42,7 +42,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops) { -@@ -688,6 +709,9 @@ int ath9k_init_device(u16 devid, struct +@@ -689,6 +710,9 @@ int ath9k_init_device(u16 devid, struct common = ath9k_hw_common(ah); ath9k_set_hw_capab(sc, hw); @@ -54,7 +54,7 @@ ath9k_reg_notifier); --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h -@@ -510,6 +510,8 @@ struct ath_softc { +@@ -511,6 +511,8 @@ struct ath_softc { struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; struct ath_btcoex btcoex; diff --git a/package/mac80211/patches/410-ath9k-wndr3700-led-pin-fix.patch b/package/mac80211/patches/410-ath9k-wndr3700-led-pin-fix.patch new file mode 100644 index 000000000..c5cc6b7e1 --- /dev/null +++ b/package/mac80211/patches/410-ath9k-wndr3700-led-pin-fix.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -138,7 +138,9 @@ void ath_init_leds(struct ath_softc *sc) + if (AR_SREV_9100(sc->sc_ah)) + return; + +- if (AR_SREV_9287(sc->sc_ah)) ++ if (sc->quirk_wndr3700) ++ sc->sc_ah->led_pin = ATH_LED_PIN_WNDR3700; ++ else if (AR_SREV_9287(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9287; + else + sc->sc_ah->led_pin = ATH_LED_PIN_DEF; +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -379,6 +379,7 @@ void ath9k_btcoex_timer_pause(struct ath + + #define ATH_LED_PIN_DEF 1 + #define ATH_LED_PIN_9287 8 ++#define ATH_LED_PIN_WNDR3700 5 + #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ + #define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ + diff --git a/package/mac80211/patches/520-ath9k_ack_timeout_workaround.patch b/package/mac80211/patches/520-ath9k_ack_timeout_workaround.patch deleted file mode 100644 index f489f0ff4..000000000 --- a/package/mac80211/patches/520-ath9k_ack_timeout_workaround.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/drivers/net/wireless/ath/ath9k/hw.c -+++ b/drivers/net/wireless/ath/ath9k/hw.c -@@ -1233,6 +1233,17 @@ void ath9k_hw_init_global_settings(struc - /* As defined by IEEE 802.11-2007 17.3.8.6 */ - slottime = ah->slottime + 3 * ah->coverage_class; - acktimeout = slottime + sifstime; -+ -+ /* -+ * Workaround for early ACK timeouts, add an offset to match the -+ * initval's 64us ack timeout value. -+ * This was initially only meant to work around an issue with delayed -+ * BA frames in some implementations, but it has been found to fix ACK -+ * timeout issues in other cases as well. -+ */ -+ if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) -+ acktimeout += 64 - sifstime - ah->slottime; -+ - ath9k_hw_setslottime(ah, slottime); - ath9k_hw_set_ack_timeout(ah, acktimeout); - ath9k_hw_set_cts_timeout(ah, acktimeout); diff --git a/package/mac80211/patches/530-cfg80211_get_freq.patch b/package/mac80211/patches/520-cfg80211_get_freq.patch similarity index 94% rename from package/mac80211/patches/530-cfg80211_get_freq.patch rename to package/mac80211/patches/520-cfg80211_get_freq.patch index a2fb29ee2..928cf4042 100644 --- a/package/mac80211/patches/530-cfg80211_get_freq.patch +++ b/package/mac80211/patches/520-cfg80211_get_freq.patch @@ -20,7 +20,7 @@ } --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c -@@ -881,6 +881,11 @@ static int nl80211_send_iface(struct sk_ +@@ -885,6 +885,11 @@ static int nl80211_send_iface(struct sk_ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); diff --git a/package/mac80211/patches/530-ath9k_rc_fallback.patch b/package/mac80211/patches/530-ath9k_rc_fallback.patch new file mode 100644 index 000000000..1b74eb5b1 --- /dev/null +++ b/package/mac80211/patches/530-ath9k_rc_fallback.patch @@ -0,0 +1,55 @@ +--- a/drivers/net/wireless/ath/ath9k/rc.c ++++ b/drivers/net/wireless/ath/ath9k/rc.c +@@ -668,7 +668,7 @@ static void ath_get_rate(void *priv, str + struct ieee80211_tx_rate *rates = tx_info->control.rates; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + __le16 fc = hdr->frame_control; +- u8 try_per_rate, i = 0, rix, nrix; ++ u8 try_per_rate, i = 0, rix; + int is_probe = 0; + + if (rate_control_send_low(sta, priv_sta, txrc)) +@@ -688,26 +688,25 @@ static void ath_get_rate(void *priv, str + + rate_table = sc->cur_rate_table; + rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); +- nrix = rix; + + if (is_probe) { + /* set one try for probe rates. For the + * probes don't enable rts */ + ath_rc_rate_set_series(rate_table, &rates[i++], txrc, +- 1, nrix, 0); ++ 1, rix, 0); + + /* Get the next tried/allowed rate. No RTS for the next series + * after the probe rate + */ +- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix); ++ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix); + ath_rc_rate_set_series(rate_table, &rates[i++], txrc, +- try_per_rate, nrix, 0); ++ try_per_rate, rix, 0); + + tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + } else { + /* Set the choosen rate. No RTS for first series entry. */ + ath_rc_rate_set_series(rate_table, &rates[i++], txrc, +- try_per_rate, nrix, 0); ++ try_per_rate, rix, 0); + } + + /* Fill in the other rates for multirate retry */ +@@ -716,10 +715,10 @@ static void ath_get_rate(void *priv, str + if (i + 1 == 4) + try_per_rate = 8; + +- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix); ++ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix); + /* All other rates in the series have RTS enabled */ + ath_rc_rate_set_series(rate_table, &rates[i], txrc, +- try_per_rate, nrix, 1); ++ try_per_rate, rix, 1); + } + + /* diff --git a/package/mac80211/patches/540-ath9k_beacon_timer_fix.patch b/package/mac80211/patches/540-ath9k_beacon_timer_fix.patch new file mode 100644 index 000000000..cc0ad7b48 --- /dev/null +++ b/package/mac80211/patches/540-ath9k_beacon_timer_fix.patch @@ -0,0 +1,22 @@ +--- a/drivers/net/wireless/ath/ath9k/beacon.c ++++ b/drivers/net/wireless/ath/ath9k/beacon.c +@@ -526,16 +526,13 @@ static void ath_beacon_config_ap(struct + { + u32 nexttbtt, intval; + +- /* Configure the timers only when the TSF has to be reset */ +- +- if (!(sc->sc_flags & SC_OP_TSF_RESET)) +- return; +- + /* NB: the beacon interval is kept internally in TU's */ + intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval /= ATH_BCBUF; /* for staggered beacons */ + nexttbtt = intval; +- intval |= ATH9K_BEACON_RESET_TSF; ++ ++ if (sc->sc_flags & SC_OP_TSF_RESET) ++ intval |= ATH9K_BEACON_RESET_TSF; + + /* + * In AP mode we enable the beacon timers and SWBA interrupts to diff --git a/package/mac80211/patches/540-ath9k_fix_eap_handling.patch b/package/mac80211/patches/540-ath9k_fix_eap_handling.patch deleted file mode 100644 index 75e5e938c..000000000 --- a/package/mac80211/patches/540-ath9k_fix_eap_handling.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/drivers/net/wireless/ath/ath9k/xmit.c -+++ b/drivers/net/wireless/ath/ath9k/xmit.c -@@ -1610,7 +1610,7 @@ static int ath_tx_setup_buffer(struct ie - bf->bf_frmlen -= padsize; - } - -- if (conf_is_ht(&hw->conf) && !is_pae(skb)) -+ if (conf_is_ht(&hw->conf)) - bf->bf_state.bf_type |= BUF_HT; - - bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); -@@ -1696,7 +1696,7 @@ static void ath_tx_start_dma(struct ath_ - goto tx_done; - } - -- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { -+ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && !is_pae(skb)) { - /* - * Try aggregation if it's a unicast data frame - * and the destination is HT capable. diff --git a/package/mac80211/patches/550-ath9k_rifs_disable.patch b/package/mac80211/patches/550-ath9k_rifs_disable.patch new file mode 100644 index 000000000..57441b643 --- /dev/null +++ b/package/mac80211/patches/550-ath9k_rifs_disable.patch @@ -0,0 +1,31 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1326,6 +1326,16 @@ static void ath9k_hw_override_ini(struct + * Necessary to avoid issues on AR5416 2.0 + */ + REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); ++ ++ /* ++ * Disable RIFS search on some chips to avoid baseband ++ * hang issues. ++ */ ++ if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) { ++ val = REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS); ++ val &= ~AR_PHY_RIFS_INIT_DELAY; ++ REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val); ++ } + } + + static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, +--- a/drivers/net/wireless/ath/ath9k/phy.h ++++ b/drivers/net/wireless/ath/ath9k/phy.h +@@ -384,6 +384,9 @@ bool ath9k_hw_set_rf_regs(struct ath_hw + + #define AR_PHY_HEAVY_CLIP_ENABLE 0x99E0 + ++#define AR_PHY_HEAVY_CLIP_FACTOR_RIFS 0x99EC ++#define AR_PHY_RIFS_INIT_DELAY 0x03ff0000 ++ + #define AR_PHY_M_SLEEP 0x99f0 + #define AR_PHY_REFCLKDLY 0x99f4 + #define AR_PHY_REFCLKPD 0x99f8 diff --git a/package/madwifi/patches/458-ibss_wpa_none.patch b/package/madwifi/patches/458-ibss_wpa_none.patch new file mode 100644 index 000000000..df77510b2 --- /dev/null +++ b/package/madwifi/patches/458-ibss_wpa_none.patch @@ -0,0 +1,13 @@ +--- a/net80211/ieee80211_crypto_ccmp.c ++++ b/net80211/ieee80211_crypto_ccmp.c +@@ -273,7 +273,9 @@ ccmp_decap(struct ieee80211_key *k, stru + tid = ((struct ieee80211_qosframe *)wh)->i_qos[0] & IEEE80211_QOS_TID; + /* NB: assume IEEE80211_WEP_MINLEN covers the extended IV */ + pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]); +- if (pn && pn <= k->wk_keyrsc[tid]) { ++ if ((vap->iv_opmode != IEEE80211_M_IBSS) && ++ (vap->iv_opmode != IEEE80211_M_AHDEMO) && ++ (pn && pn <= k->wk_keyrsc[tid])) { + /* + * Replay violation. + */ diff --git a/package/opkg/Makefile b/package/opkg/Makefile index 243e0b6d3..6894ae7cb 100644 --- a/package/opkg/Makefile +++ b/package/opkg/Makefile @@ -70,7 +70,7 @@ define Package/opkg/install $(INSTALL_DIR) $(1)/bin $(INSTALL_DIR) $(1)/etc $(INSTALL_DATA) ./files/opkg.conf $(1)/etc/ - $(SED) 's,$$$$S,$(TARGET),g' $(1)/etc/opkg.conf + $(SED) 's,$$$$S,$(PKGARCH),g' $(1)/etc/opkg.conf $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/opkg-cl $(1)/bin/opkg endef diff --git a/package/ppp/patches/200-makefile.patch b/package/ppp/patches/200-makefile.patch index e9731d1e0..af826749c 100644 --- a/package/ppp/patches/200-makefile.patch +++ b/package/ppp/patches/200-makefile.patch @@ -1,6 +1,6 @@ --- a/pppd/Makefile.linux +++ b/pppd/Makefile.linux -@@ -48,21 +48,21 @@ MPPE=y +@@ -48,7 +48,7 @@ MPPE=y # Uncomment the next line to include support for PPP packet filtering. # This requires that the libpcap library and headers be installed # and that the kernel driver support PPP packet filtering. @@ -9,10 +9,7 @@ # Uncomment the next line to enable multilink PPP (enabled by default) # Linux distributions: Please leave multilink ENABLED in your builds - # of pppd! --HAVE_MULTILINK=y -+#HAVE_MULTILINK=y - +@@ -58,11 +58,11 @@ HAVE_MULTILINK=y # Uncomment the next line to enable the TDB database (enabled by default.) # If you enable multilink, then TDB is automatically enabled also. # Linux distributions: Please leave TDB ENABLED in your builds. diff --git a/package/r8101/Makefile b/package/r8101/Makefile index 370a9aebf..0e6f08d42 100644 --- a/package/r8101/Makefile +++ b/package/r8101/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2009 OpenWrt.org +# Copyright (C) 2009-2010 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -9,19 +9,22 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=r8101 -PKG_VERSION:=1.012.00 +PKG_VERSION:=1.014.00 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 -PKG_SOURCE_URL:=ftp://WebUser:nQJ4P7b@202.65.194.212/cn/nic/ -PKG_MD5SUM:=eb0645af023926f3ab8d0d40f68748ef +PKG_SOURCE_URL:= \ + ftp://WebUser:nQJ4P7b@202.134.71.22/cn/nic/ \ + ftp://WebUser:nQJ4P7b@66.104.77.130/cn/nic/ \ + ftp://WebUser:nQJ4P7b@61.56.86.122/cn/nic/ +PKG_MD5SUM:=dace75093a1439310750029ccebe2c15 include $(INCLUDE_DIR)/package.mk define KernelPackage/r8101 SUBMENU:=Network Devices TITLE:=RealTek RTL-8101E PCIe Fast Ethernet Adapter kernel support - DEPENDS:=@TARGET_x86 @!LINUX_2_6_31 + DEPENDS:=@TARGET_x86 URL:=http://www.realtek.com.tw/ FILES:= $(PKG_BUILD_DIR)/src/r8101.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,50,r8101) @@ -31,12 +34,15 @@ define KernelPackage/r8101/description Kernel modules for RealTek RTL-8101E PCI-Express Fast Ethernet adapters. endef +include $(INCLUDE_DIR)/kernel-defaults.mk + +define Build/Configure +endef + define Build/Compile chmod u+x $(PKG_BUILD_DIR)/src - $(MAKE) -C $(LINUX_DIR) \ - SUBDIRS="$(PKG_BUILD_DIR)/src" \ - ARCH="$(LINUX_KARCH)" \ - CROSS_COMPILE="$(TARGET_CROSS)" \ + $(MAKE) $(KERNEL_MAKEOPTS) \ + M="$(PKG_BUILD_DIR)/src" \ modules endef diff --git a/package/swconfig/src/cli.c b/package/swconfig/src/cli.c index 7e77bd2c6..76593ba14 100644 --- a/package/swconfig/src/cli.c +++ b/package/swconfig/src/cli.c @@ -196,8 +196,6 @@ int main(int argc, char **argv) int err; int i; - struct switch_port *ports; - int cmd = CMD_NONE; char *cdev = NULL; int cport = -1; @@ -255,8 +253,6 @@ int main(int argc, char **argv) return 1; } - ports = malloc(sizeof(struct switch_port) * dev->ports); - memset(ports, 0, sizeof(struct switch_port) * dev->ports); swlib_scan(dev); if (cmd == CMD_GET || cmd == CMD_SET) { @@ -329,7 +325,5 @@ int main(int argc, char **argv) out: swlib_free_all(dev); - free(ports); - return 0; } diff --git a/package/vsc73x5-ucode/Makefile b/package/vsc73x5-ucode/Makefile new file mode 100644 index 000000000..d48af0026 --- /dev/null +++ b/package/vsc73x5-ucode/Makefile @@ -0,0 +1,102 @@ +# +# Copyright (C) 2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=vsc73x5-ucode +PKG_RELEASE:=1 + +PKG_SOURCE_URL:=http://www.tp-link.com/GPL + +PKG_SOURCE:=WirelessNRouer_AP.tar.gz +PKG_BUILD_DIR:=$(BUILD_DIR)/vsc73x5-ucode + +PKG_MD5SUM:=7dd6069a5f0e44cc9965fc7b43eb3046 + +UCODE_SRC_DIR:=u-boot/board/ar7100/common +UCODE_BUILD_DIR:=$(PKG_BUILD_DIR)/$(UCODE_SRC_DIR) + +include $(INCLUDE_DIR)/package.mk + +define Package/vsc73x5-defaults + SECTION:=net + CATEGORY:=Network + DEPENDS:=@TARGET_ar71xx + DEFAULT:=n + TITLE:=$(1) +endef + +define Package/vsc73x5/install + $(INSTALL_DIR) $(1)/lib/firmware + $(INSTALL_DATA) $(UCODE_BUILD_DIR)/$(2) $(1)/lib/firmware/$(3) +endef + +define Package/vsc7385-ucode-ap83 + $(call Package/vsc73x5-defaults,Vitesse VSC7385 microcode for the Atheros AP83 boards) +endef + +define Package/vsc7385-ucode-ap83/description + This package contains the Atheros AP83 board specific microcode for + the Vitesse VSC7385 ethernet switch. +endef + +define Package/vsc7385-ucode-ap83/install + $(call Package/vsc73x5/install,$(1),g5_Plus1_2_31_unmanaged_Atheros_v3.bin,vsc7385_ucode_ap83.bin) +endef + +define Package/vsc7395-ucode-ap83 + $(call Package/vsc73x5-defaults, Vitesse VSC7395 microcode for the Atheros AP83 boards) +endef + +define Package/vsc7395-ucode-ap83/description + This package contains the Atheros AP83 board specific microcode for + the Vitesse VSC7395 ethernet switch. +endef + +define Package/vsc7395-ucode-ap83/install + $(call Package/vsc73x5/install,$(1),g5_Plus1_2_31_unmanaged_Atheros_v4.bin,vsc7395_ucode_ap83.bin) +endef + +define Package/vsc7385-ucode-pb44 + $(call Package/vsc73x5-defaults, Vitesse VSC7395 microcode for the Atheros PB44 boards) +endef + +define Package/vsc7385-ucode-pb44/description + This package contains the Atheros PB44 board specific microcode for + the Vitesse VSC7385 ethernet switch. +endef + +define Package/vsc7385-ucode-pb44/install + $(call Package/vsc73x5/install,$(1),g5_Plus1_2_29b_unmanaged_Atheros_v5.bin,vsc7385_ucode_pb44.bin) +endef + +define Package/vsc7395-ucode-pb44 + $(call Package/vsc73x5-defaults, Vitesse VSC7395 microcode for the Atheros PB44 boards) +endef + +define Package/vsc7395-ucode-pb44/description + This package contains the Atheros AP83 board specific microcode for + the Vitesse VSC7395 ethernet switch. +endef + +define Package/vsc7395-ucode-pb44/install + $(call Package/vsc73x5/install,$(1),g5e_Plus1_2_29a_unmanaged_Atheros_v3.bin,vsc7395_ucode_pb44.bin) +endef + +define Build/Prepare + tar -xzf "$(DL_DIR)/$(PKG_SOURCE)" ap-9x-gpl/ap93-u-boot.tar.bz2 -O | tar -C "$(PKG_BUILD_DIR)" -xj $(UCODE_SRC_DIR) + cp files/Makefile $(UCODE_BUILD_DIR) +endef + +define Build/Compile + $(MAKE) -C $(UCODE_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) all +endef + +$(eval $(call BuildPackage,vsc7385-ucode-ap83)) +$(eval $(call BuildPackage,vsc7395-ucode-ap83)) +$(eval $(call BuildPackage,vsc7385-ucode-pb44)) +$(eval $(call BuildPackage,vsc7395-ucode-pb44)) diff --git a/package/vsc73x5-ucode/files/Makefile b/package/vsc73x5-ucode/files/Makefile new file mode 100644 index 000000000..550f51df7 --- /dev/null +++ b/package/vsc73x5-ucode/files/Makefile @@ -0,0 +1,20 @@ +# +# Copyright (C) 2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +CC:=gcc +OBJCOPY:=objcopy + +all: g5_Plus1_2_31_unmanaged_Atheros_v3.bin \ + g5_Plus1_2_31_unmanaged_Atheros_v4.bin \ + g5_Plus1_2_29b_unmanaged_Atheros_v5.bin \ + g5e_Plus1_2_29a_unmanaged_Atheros_v3.bin + +%.o: %.c + $(CC) $(CFLAGS) -c $^ -o $@ + +%.bin: %.o + $(OBJCOPY) -O binary -j .data $^ $@ diff --git a/rules.mk b/rules.mk index 3473b212d..47db7f62d 100644 --- a/rules.mk +++ b/rules.mk @@ -80,7 +80,6 @@ STAMP_DIR_HOST=$(BUILD_DIR_HOST)/stamp TARGET_ROOTFS_DIR?=$(if $(call qstrip,$(CONFIG_TARGET_ROOTFS_DIR)),$(call qstrip,$(CONFIG_TARGET_ROOTFS_DIR)),$(BUILD_DIR)) TARGET_DIR:=$(TARGET_ROOTFS_DIR)/root-$(BOARD) STAGING_DIR_ROOT:=$(STAGING_DIR)/root-$(BOARD) -DEBUG_DIR:=$(BUILD_DIR)/debug-$(BOARD) BUILD_LOG_DIR:=$(TOPDIR)/logs TARGET_PATH:=$(STAGING_DIR_HOST)/bin:$(PATH) @@ -220,6 +219,10 @@ $(call shvar,$(1))=$$(call $(1)) export $(call shvar,$(1)) endef +define include_mk +$(eval -include $(if $(DUMP),,$(STAGING_DIR)/mk/$(strip $(1)))) +endef + # file extension ext=$(word $(words $(subst ., ,$(1))),$(subst ., ,$(1))) diff --git a/scripts/remote-gdb b/scripts/remote-gdb index 869fa875a..9701b31c1 100755 --- a/scripts/remote-gdb +++ b/scripts/remote-gdb @@ -53,8 +53,9 @@ if( opendir SD, "$Bin/../staging_dir" ) # Find library paths my $libdirs = join ':', ( - glob("$Bin/../staging_dir/target-${arch}_${libc}/{usr/,}lib"), - glob("$Bin/../staging_dir/toolchain-${arch}_*_${libc}/lib") + glob("$Bin/../staging_dir/target-${arch}_${libc}/root-*/{,usr/}lib/"), + glob("$Bin/../staging_dir/target-${arch}_${libc}/{,usr/}lib/"), + glob("$Bin/../staging_dir/toolchain-${arch}_*_${libc}/lib/") ); print $fh "set solib-search-path $libdirs\n"; diff --git a/target/linux/adm5120/router_be/config-2.6.30 b/target/linux/adm5120/router_be/config-2.6.30 index 71703aacb..931987495 100644 --- a/target/linux/adm5120/router_be/config-2.6.30 +++ b/target/linux/adm5120/router_be/config-2.6.30 @@ -1,5 +1,6 @@ CONFIG_32BIT=y # CONFIG_64BIT is not set +CONFIG_ADM5120=y CONFIG_ADM5120_ENET=y CONFIG_ADM5120_MACH_5GXI=y CONFIG_ADM5120_MACH_P_334WT=y @@ -14,7 +15,6 @@ CONFIG_ADM5120_OEM_OSBRIDGE=y CONFIG_ADM5120_OEM_ZYXEL=y CONFIG_ADM5120_SOC_BGA=y CONFIG_ADM5120_WDT=y -CONFIG_ADM5120=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_ARCH_POPULATES_NODE_MAP=y @@ -30,8 +30,8 @@ CONFIG_BITREVERSE=y # CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set # CONFIG_CAVIUM_OCTEON_SIMULATOR is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_CEVT_R4K_LIB=y CONFIG_CEVT_R4K=y +CONFIG_CEVT_R4K_LIB=y CONFIG_CMDLINE="console=ttyS0,115200 rootfstype=squashfs,jffs2" CONFIG_CPU_BIG_ENDIAN=y # CONFIG_CPU_CAVIUM_OCTEON is not set @@ -40,9 +40,9 @@ CONFIG_CPU_HAS_PREFETCH=y CONFIG_CPU_HAS_SYNC=y # CONFIG_CPU_LITTLE_ENDIAN is not set # CONFIG_CPU_LOONGSON2 is not set +CONFIG_CPU_MIPS32=y CONFIG_CPU_MIPS32_R1=y # CONFIG_CPU_MIPS32_R2 is not set -CONFIG_CPU_MIPS32=y # CONFIG_CPU_MIPS64_R1 is not set # CONFIG_CPU_MIPS64_R2 is not set CONFIG_CPU_MIPSR1=y @@ -64,8 +64,8 @@ CONFIG_CPU_SUPPORTS_HIGHMEM=y # CONFIG_CPU_TX39XX is not set # CONFIG_CPU_TX49XX is not set # CONFIG_CPU_VR41XX is not set -CONFIG_CSRC_R4K_LIB=y CONFIG_CSRC_R4K=y +CONFIG_CSRC_R4K_LIB=y CONFIG_DECOMPRESS_LZMA=y CONFIG_DEVPORT=y # CONFIG_DM9000 is not set @@ -76,8 +76,8 @@ CONFIG_ELF_CORE=y CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_FS_POSIX_ACL=y CONFIG_GENERIC_ACL=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_FIND_LAST_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y @@ -98,20 +98,20 @@ CONFIG_HID=m CONFIG_HID_SUPPORT=y CONFIG_HW_HAS_PCI=y CONFIG_HW_RANDOM=y -# CONFIG_HZ_100 is not set CONFIG_HZ=250 +# CONFIG_HZ_100 is not set CONFIG_HZ_250=y CONFIG_INITRAMFS_SOURCE="" -CONFIG_INOTIFY_USER=y CONFIG_INOTIFY=y -# CONFIG_INPUT_GPIO_BUTTONS is not set +CONFIG_INOTIFY_USER=y CONFIG_INPUT=m +# CONFIG_INPUT_GPIO_BUTTONS is not set # CONFIG_INPUT_YEALINK is not set CONFIG_IRQ_CPU=y CONFIG_LEDS_GPIO=m CONFIG_LEDS_TRIGGER_ADM5120_SWITCH=m -CONFIG_LEGACY_PTY_COUNT=256 CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_LEMOTE_FULONG is not set # CONFIG_MACH_ALCHEMY is not set # CONFIG_MACH_DECSTATION is not set @@ -121,8 +121,8 @@ CONFIG_LEGACY_PTYS=y # CONFIG_MACH_VR41XX is not set CONFIG_MII=m # CONFIG_MIKROTIK_RB532 is not set +CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set -# CONFIG_MIPS_FPU_EMU is not set CONFIG_MIPS_L1_CACHE_SHIFT=5 CONFIG_MIPS_MACHINE=y # CONFIG_MIPS_MALTA is not set @@ -130,7 +130,6 @@ CONFIG_MIPS_MT_DISABLED=y # CONFIG_MIPS_MT_SMP is not set # CONFIG_MIPS_MT_SMTC is not set # CONFIG_MIPS_SIM is not set -CONFIG_MIPS=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MTD_ADM5120=y CONFIG_MTD_BLOCK2MTD=y @@ -154,18 +153,18 @@ CONFIG_PCI_DOMAINS=y CONFIG_SCHED_OMIT_FRAME_POINTER=y # CONFIG_SCSI_DMA is not set # CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_AMBA_PL010=y CONFIG_SERIAL_AMBA_PL010_CONSOLE=y CONFIG_SERIAL_AMBA_PL010_NUMPORTS=2 CONFIG_SERIAL_AMBA_PL010_PORTNAME="ttyS" -CONFIG_SERIAL_AMBA_PL010=y # CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIO=y # CONFIG_SERIO_AMBAKMI is not set # CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_PCIPS2 is not set # CONFIG_SERIO_RAW is not set CONFIG_SERIO_SERPORT=y -CONFIG_SERIO=y # CONFIG_SGI_IP22 is not set # CONFIG_SGI_IP27 is not set # CONFIG_SGI_IP28 is not set @@ -192,10 +191,10 @@ CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_TRACING_SUPPORT=y CONFIG_TRAD_SIGNALS=y +CONFIG_USB=m CONFIG_USB_ADM5120_HCD=m CONFIG_USB_DEBUG=y CONFIG_USB_EHCI_HCD=m -CONFIG_USB=m # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set CONFIG_USB_OHCI_HCD=m diff --git a/target/linux/adm5120/router_be/config-2.6.32 b/target/linux/adm5120/router_be/config-2.6.32 index 13ecb910f..f919e0d66 100644 --- a/target/linux/adm5120/router_be/config-2.6.32 +++ b/target/linux/adm5120/router_be/config-2.6.32 @@ -1,5 +1,6 @@ CONFIG_32BIT=y # CONFIG_64BIT is not set +CONFIG_ADM5120=y CONFIG_ADM5120_ENET=y CONFIG_ADM5120_MACH_5GXI=y CONFIG_ADM5120_MACH_P_334WT=y @@ -14,7 +15,6 @@ CONFIG_ADM5120_OEM_OSBRIDGE=y CONFIG_ADM5120_OEM_ZYXEL=y CONFIG_ADM5120_SOC_BGA=y CONFIG_ADM5120_WDT=y -CONFIG_ADM5120=y # CONFIG_ALCHEMY_GPIO_INDIRECT is not set # CONFIG_AR7 is not set # CONFIG_ARCH_HAS_ILOG2_U32 is not set @@ -33,8 +33,8 @@ CONFIG_BITREVERSE=y # CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set # CONFIG_CAVIUM_OCTEON_SIMULATOR is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_CEVT_R4K_LIB=y CONFIG_CEVT_R4K=y +CONFIG_CEVT_R4K_LIB=y CONFIG_CFG80211_DEFAULT_PS_VALUE=0 CONFIG_CMDLINE="console=ttyS0,115200 rootfstype=squashfs,jffs2" CONFIG_CPU_BIG_ENDIAN=y @@ -43,9 +43,9 @@ CONFIG_CPU_HAS_PREFETCH=y CONFIG_CPU_HAS_SYNC=y # CONFIG_CPU_LITTLE_ENDIAN is not set # CONFIG_CPU_LOONGSON2E is not set +CONFIG_CPU_MIPS32=y CONFIG_CPU_MIPS32_R1=y # CONFIG_CPU_MIPS32_R2 is not set -CONFIG_CPU_MIPS32=y # CONFIG_CPU_MIPS64_R1 is not set # CONFIG_CPU_MIPS64_R2 is not set CONFIG_CPU_MIPSR1=y @@ -67,8 +67,8 @@ CONFIG_CPU_SUPPORTS_HIGHMEM=y # CONFIG_CPU_TX39XX is not set # CONFIG_CPU_TX49XX is not set # CONFIG_CPU_VR41XX is not set -CONFIG_CSRC_R4K_LIB=y CONFIG_CSRC_R4K=y +CONFIG_CSRC_R4K_LIB=y CONFIG_DECOMPRESS_LZMA=y CONFIG_DEVPORT=y # CONFIG_DM9000 is not set @@ -79,8 +79,8 @@ CONFIG_ELF_CORE=y CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_FS_POSIX_ACL=y CONFIG_GENERIC_ACL=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_FIND_LAST_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y @@ -101,20 +101,20 @@ CONFIG_HID=m CONFIG_HID_SUPPORT=y CONFIG_HW_HAS_PCI=y CONFIG_HW_RANDOM=y -# CONFIG_HZ_100 is not set CONFIG_HZ=250 +# CONFIG_HZ_100 is not set CONFIG_HZ_250=y CONFIG_INITRAMFS_SOURCE="" -CONFIG_INOTIFY_USER=y CONFIG_INOTIFY=y -# CONFIG_INPUT_GPIO_BUTTONS is not set +CONFIG_INOTIFY_USER=y CONFIG_INPUT=m +# CONFIG_INPUT_GPIO_BUTTONS is not set # CONFIG_INPUT_YEALINK is not set CONFIG_IRQ_CPU=y CONFIG_LEDS_GPIO=m CONFIG_LEDS_TRIGGER_ADM5120_SWITCH=m -CONFIG_LEGACY_PTY_COUNT=256 CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_MACH_ALCHEMY is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MACH_JAZZ is not set @@ -124,6 +124,7 @@ CONFIG_LEGACY_PTYS=y # CONFIG_MACH_VR41XX is not set CONFIG_MII=m # CONFIG_MIKROTIK_RB532 is not set +CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set CONFIG_MIPS_L1_CACHE_SHIFT=5 CONFIG_MIPS_MACHINE=y @@ -132,7 +133,6 @@ CONFIG_MIPS_MT_DISABLED=y # CONFIG_MIPS_MT_SMP is not set # CONFIG_MIPS_MT_SMTC is not set # CONFIG_MIPS_SIM is not set -CONFIG_MIPS=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MTD_ADM5120=y CONFIG_MTD_BLOCK2MTD=y @@ -157,18 +157,18 @@ CONFIG_PCI_DOMAINS=y CONFIG_SCHED_OMIT_FRAME_POINTER=y # CONFIG_SCSI_DMA is not set # CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_AMBA_PL010=y CONFIG_SERIAL_AMBA_PL010_CONSOLE=y CONFIG_SERIAL_AMBA_PL010_NUMPORTS=2 CONFIG_SERIAL_AMBA_PL010_PORTNAME="ttyS" -CONFIG_SERIAL_AMBA_PL010=y # CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIO=y # CONFIG_SERIO_AMBAKMI is not set # CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_PCIPS2 is not set # CONFIG_SERIO_RAW is not set CONFIG_SERIO_SERPORT=y -CONFIG_SERIO=y # CONFIG_SGI_IP22 is not set # CONFIG_SGI_IP27 is not set # CONFIG_SGI_IP28 is not set @@ -195,10 +195,10 @@ CONFIG_TMPFS_POSIX_ACL=y CONFIG_TRAD_SIGNALS=y # CONFIG_TREE_PREEMPT_RCU is not set CONFIG_TREE_RCU=y +CONFIG_USB=m CONFIG_USB_ADM5120_HCD=m CONFIG_USB_DEBUG=y CONFIG_USB_EHCI_HCD=m -CONFIG_USB=m # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set CONFIG_USB_OHCI_HCD=m diff --git a/target/linux/adm5120/router_le/config-2.6.30 b/target/linux/adm5120/router_le/config-2.6.30 index 793f96173..d6f98f7ac 100644 --- a/target/linux/adm5120/router_le/config-2.6.30 +++ b/target/linux/adm5120/router_le/config-2.6.30 @@ -1,9 +1,10 @@ CONFIG_32BIT=y # CONFIG_64BIT is not set +CONFIG_ADM5120=y CONFIG_ADM5120_ENET=y CONFIG_ADM5120_MACH_5GXI=y -CONFIG_ADM5120_MACH_BR_6104KP=y CONFIG_ADM5120_MACH_BR_6104K=y +CONFIG_ADM5120_MACH_BR_6104KP=y CONFIG_ADM5120_MACH_BR_61X4WG=y CONFIG_ADM5120_MACH_CAS_771=y CONFIG_ADM5120_MACH_EASY5120P_ATA=y @@ -15,8 +16,8 @@ CONFIG_ADM5120_MACH_NP27G=y CONFIG_ADM5120_MACH_NP28G=y CONFIG_ADM5120_MACH_PMUGW=y CONFIG_ADM5120_MACH_RB_11X=y -CONFIG_ADM5120_MACH_RB_133C=y CONFIG_ADM5120_MACH_RB_133=y +CONFIG_ADM5120_MACH_RB_133C=y CONFIG_ADM5120_MACH_RB_150=y CONFIG_ADM5120_MACH_RB_153=y CONFIG_ADM5120_MACH_RB_192=y @@ -31,7 +32,6 @@ CONFIG_ADM5120_OEM_OSBRIDGE=y # CONFIG_ADM5120_OEM_ZYXEL is not set CONFIG_ADM5120_SOC_BGA=y CONFIG_ADM5120_WDT=y -CONFIG_ADM5120=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_ARCH_POPULATES_NODE_MAP=y @@ -47,8 +47,8 @@ CONFIG_BITREVERSE=y # CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set # CONFIG_CAVIUM_OCTEON_SIMULATOR is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_CEVT_R4K_LIB=y CONFIG_CEVT_R4K=y +CONFIG_CEVT_R4K_LIB=y CONFIG_CMDLINE="console=ttyS0,115200 rootfstype=squashfs,yaffs2,jffs2" # CONFIG_CPU_BIG_ENDIAN is not set # CONFIG_CPU_CAVIUM_OCTEON is not set @@ -57,9 +57,9 @@ CONFIG_CPU_HAS_PREFETCH=y CONFIG_CPU_HAS_SYNC=y CONFIG_CPU_LITTLE_ENDIAN=y # CONFIG_CPU_LOONGSON2 is not set +CONFIG_CPU_MIPS32=y CONFIG_CPU_MIPS32_R1=y # CONFIG_CPU_MIPS32_R2 is not set -CONFIG_CPU_MIPS32=y # CONFIG_CPU_MIPS64_R1 is not set # CONFIG_CPU_MIPS64_R2 is not set CONFIG_CPU_MIPSR1=y @@ -84,18 +84,18 @@ CONFIG_CPU_SUPPORTS_HIGHMEM=y CONFIG_CRYPTO_AEAD2=y CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_BLKCIPHER2=y CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLKCIPHER2=y CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_HASH2=y CONFIG_CRYPTO_HASH=m -CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_HASH2=y CONFIG_CRYPTO_MANAGER=m +CONFIG_CRYPTO_MANAGER2=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RNG2=y CONFIG_CRYPTO_WORKQUEUE=y -CONFIG_CSRC_R4K_LIB=y CONFIG_CSRC_R4K=y +CONFIG_CSRC_R4K_LIB=y CONFIG_DECOMPRESS_LZMA=y CONFIG_DEVPORT=y # CONFIG_DM9000 is not set @@ -106,8 +106,8 @@ CONFIG_ELF_CORE=y CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_FS_POSIX_ACL=y CONFIG_GENERIC_ACL=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_FIND_LAST_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y @@ -127,33 +127,33 @@ CONFIG_HAVE_MLOCK=y CONFIG_HAVE_OPROFILE=y CONFIG_HID=m CONFIG_HID_SUPPORT=y -# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set -CONFIG_HOSTAP_FIRMWARE=y CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set CONFIG_HOSTAP_PCI=m CONFIG_HW_HAS_PCI=y CONFIG_HW_RANDOM=y -# CONFIG_HZ_100 is not set CONFIG_HZ=250 +# CONFIG_HZ_100 is not set CONFIG_HZ_250=y CONFIG_IMAGE_CMDLINE_HACK=y CONFIG_INITRAMFS_SOURCE="" -CONFIG_INOTIFY_USER=y CONFIG_INOTIFY=y -# CONFIG_INPUT_GPIO_BUTTONS is not set +CONFIG_INOTIFY_USER=y CONFIG_INPUT=m +# CONFIG_INPUT_GPIO_BUTTONS is not set # CONFIG_INPUT_YEALINK is not set CONFIG_IRQ_CPU=y CONFIG_KEXEC=y CONFIG_LEDS_GPIO=m CONFIG_LEDS_TRIGGER_ADM5120_SWITCH=m -CONFIG_LEGACY_PTY_COUNT=256 CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_LEMOTE_FULONG is not set +CONFIG_LIB80211=m CONFIG_LIB80211_CRYPT_CCMP=m CONFIG_LIB80211_CRYPT_TKIP=m CONFIG_LIB80211_CRYPT_WEP=m -CONFIG_LIB80211=m # CONFIG_MACH_ALCHEMY is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MACH_JAZZ is not set @@ -162,8 +162,8 @@ CONFIG_LIB80211=m # CONFIG_MACH_VR41XX is not set CONFIG_MII=m # CONFIG_MIKROTIK_RB532 is not set +CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set -# CONFIG_MIPS_FPU_EMU is not set CONFIG_MIPS_L1_CACHE_SHIFT=5 CONFIG_MIPS_MACHINE=y # CONFIG_MIPS_MALTA is not set @@ -171,7 +171,6 @@ CONFIG_MIPS_MT_DISABLED=y # CONFIG_MIPS_MT_SMP is not set # CONFIG_MIPS_MT_SMTC is not set # CONFIG_MIPS_SIM is not set -CONFIG_MIPS=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MTD_ADM5120=y CONFIG_MTD_CFI_FIXUP_MACRONIX_BOOTLOC=y @@ -179,8 +178,8 @@ CONFIG_MTD_CFI_FIXUP_MACRONIX_BOOTLOC=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_MYLOADER_PARTS=y -CONFIG_MTD_NAND_PLATFORM=y CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_PLATFORM=y CONFIG_MTD_TRXSPLIT=y CONFIG_NO_HZ=y # CONFIG_NO_IOPORT is not set @@ -199,18 +198,18 @@ CONFIG_PCI_DOMAINS=y CONFIG_SCHED_OMIT_FRAME_POINTER=y CONFIG_SCSI=m # CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_AMBA_PL010=y CONFIG_SERIAL_AMBA_PL010_CONSOLE=y CONFIG_SERIAL_AMBA_PL010_NUMPORTS=2 CONFIG_SERIAL_AMBA_PL010_PORTNAME="ttyS" -CONFIG_SERIAL_AMBA_PL010=y # CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIO=y # CONFIG_SERIO_AMBAKMI is not set # CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_PCIPS2 is not set # CONFIG_SERIO_RAW is not set CONFIG_SERIO_SERPORT=y -CONFIG_SERIO=y # CONFIG_SGI_IP22 is not set # CONFIG_SGI_IP27 is not set # CONFIG_SGI_IP28 is not set @@ -238,9 +237,9 @@ CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_TRACING_SUPPORT=y CONFIG_TRAD_SIGNALS=y +CONFIG_USB=m CONFIG_USB_ADM5120_HCD=m CONFIG_USB_EHCI_HCD=m -CONFIG_USB=m # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set CONFIG_USB_OHCI_HCD=m diff --git a/target/linux/adm5120/router_le/config-2.6.32 b/target/linux/adm5120/router_le/config-2.6.32 index 886b149c9..263011f9e 100644 --- a/target/linux/adm5120/router_le/config-2.6.32 +++ b/target/linux/adm5120/router_le/config-2.6.32 @@ -1,9 +1,10 @@ CONFIG_32BIT=y # CONFIG_64BIT is not set +CONFIG_ADM5120=y CONFIG_ADM5120_ENET=y CONFIG_ADM5120_MACH_5GXI=y -CONFIG_ADM5120_MACH_BR_6104KP=y CONFIG_ADM5120_MACH_BR_6104K=y +CONFIG_ADM5120_MACH_BR_6104KP=y CONFIG_ADM5120_MACH_BR_61X4WG=y CONFIG_ADM5120_MACH_CAS_771=y CONFIG_ADM5120_MACH_EASY5120P_ATA=y @@ -15,8 +16,8 @@ CONFIG_ADM5120_MACH_NP27G=y CONFIG_ADM5120_MACH_NP28G=y CONFIG_ADM5120_MACH_PMUGW=y CONFIG_ADM5120_MACH_RB_11X=y -CONFIG_ADM5120_MACH_RB_133C=y CONFIG_ADM5120_MACH_RB_133=y +CONFIG_ADM5120_MACH_RB_133C=y CONFIG_ADM5120_MACH_RB_150=y CONFIG_ADM5120_MACH_RB_153=y CONFIG_ADM5120_MACH_RB_192=y @@ -31,7 +32,6 @@ CONFIG_ADM5120_OEM_OSBRIDGE=y # CONFIG_ADM5120_OEM_ZYXEL is not set CONFIG_ADM5120_SOC_BGA=y CONFIG_ADM5120_WDT=y -CONFIG_ADM5120=y # CONFIG_ALCHEMY_GPIO_INDIRECT is not set # CONFIG_AR7 is not set # CONFIG_ARCH_HAS_ILOG2_U32 is not set @@ -50,8 +50,8 @@ CONFIG_BITREVERSE=y # CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set # CONFIG_CAVIUM_OCTEON_SIMULATOR is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_CEVT_R4K_LIB=y CONFIG_CEVT_R4K=y +CONFIG_CEVT_R4K_LIB=y CONFIG_CFG80211_DEFAULT_PS_VALUE=0 CONFIG_CMDLINE="console=ttyS0,115200 rootfstype=squashfs,yaffs2,jffs2" # CONFIG_CPU_BIG_ENDIAN is not set @@ -60,9 +60,9 @@ CONFIG_CPU_HAS_PREFETCH=y CONFIG_CPU_HAS_SYNC=y CONFIG_CPU_LITTLE_ENDIAN=y # CONFIG_CPU_LOONGSON2E is not set +CONFIG_CPU_MIPS32=y CONFIG_CPU_MIPS32_R1=y # CONFIG_CPU_MIPS32_R2 is not set -CONFIG_CPU_MIPS32=y # CONFIG_CPU_MIPS64_R1 is not set # CONFIG_CPU_MIPS64_R2 is not set CONFIG_CPU_MIPSR1=y @@ -87,18 +87,18 @@ CONFIG_CPU_SUPPORTS_HIGHMEM=y CONFIG_CRYPTO_AEAD2=y CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_BLKCIPHER2=y CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLKCIPHER2=y CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_HASH2=y CONFIG_CRYPTO_HASH=m -CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_HASH2=y CONFIG_CRYPTO_MANAGER=m +CONFIG_CRYPTO_MANAGER2=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RNG2=y CONFIG_CRYPTO_WORKQUEUE=y -CONFIG_CSRC_R4K_LIB=y CONFIG_CSRC_R4K=y +CONFIG_CSRC_R4K_LIB=y CONFIG_DECOMPRESS_LZMA=y CONFIG_DEVPORT=y # CONFIG_DM9000 is not set @@ -109,8 +109,8 @@ CONFIG_ELF_CORE=y CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_FS_POSIX_ACL=y CONFIG_GENERIC_ACL=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_FIND_LAST_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y @@ -130,32 +130,32 @@ CONFIG_HAVE_IDE=y CONFIG_HAVE_OPROFILE=y CONFIG_HID=m CONFIG_HID_SUPPORT=y -# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set -CONFIG_HOSTAP_FIRMWARE=y CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set CONFIG_HOSTAP_PCI=m CONFIG_HW_HAS_PCI=y CONFIG_HW_RANDOM=y -# CONFIG_HZ_100 is not set CONFIG_HZ=250 +# CONFIG_HZ_100 is not set CONFIG_HZ_250=y CONFIG_IMAGE_CMDLINE_HACK=y CONFIG_INITRAMFS_SOURCE="" -CONFIG_INOTIFY_USER=y CONFIG_INOTIFY=y -# CONFIG_INPUT_GPIO_BUTTONS is not set +CONFIG_INOTIFY_USER=y CONFIG_INPUT=m +# CONFIG_INPUT_GPIO_BUTTONS is not set # CONFIG_INPUT_YEALINK is not set CONFIG_IRQ_CPU=y CONFIG_KEXEC=y CONFIG_LEDS_GPIO=m CONFIG_LEDS_TRIGGER_ADM5120_SWITCH=m -CONFIG_LEGACY_PTY_COUNT=256 CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIB80211=m CONFIG_LIB80211_CRYPT_CCMP=m CONFIG_LIB80211_CRYPT_TKIP=m CONFIG_LIB80211_CRYPT_WEP=m -CONFIG_LIB80211=m # CONFIG_MACH_ALCHEMY is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MACH_JAZZ is not set @@ -165,6 +165,7 @@ CONFIG_LIB80211=m # CONFIG_MACH_VR41XX is not set CONFIG_MII=m # CONFIG_MIKROTIK_RB532 is not set +CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set CONFIG_MIPS_L1_CACHE_SHIFT=5 CONFIG_MIPS_MACHINE=y @@ -173,7 +174,6 @@ CONFIG_MIPS_MT_DISABLED=y # CONFIG_MIPS_MT_SMP is not set # CONFIG_MIPS_MT_SMTC is not set # CONFIG_MIPS_SIM is not set -CONFIG_MIPS=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MTD_ADM5120=y CONFIG_MTD_CFI_FIXUP_MACRONIX_BOOTLOC=y @@ -181,8 +181,8 @@ CONFIG_MTD_CFI_FIXUP_MACRONIX_BOOTLOC=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_MYLOADER_PARTS=y -CONFIG_MTD_NAND_PLATFORM=y CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_PLATFORM=y CONFIG_MTD_TRXSPLIT=y CONFIG_NLS=m CONFIG_NO_HZ=y @@ -202,18 +202,18 @@ CONFIG_PCI_DOMAINS=y CONFIG_SCHED_OMIT_FRAME_POINTER=y CONFIG_SCSI=m # CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_AMBA_PL010=y CONFIG_SERIAL_AMBA_PL010_CONSOLE=y CONFIG_SERIAL_AMBA_PL010_NUMPORTS=2 CONFIG_SERIAL_AMBA_PL010_PORTNAME="ttyS" -CONFIG_SERIAL_AMBA_PL010=y # CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIO=y # CONFIG_SERIO_AMBAKMI is not set # CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_PCIPS2 is not set # CONFIG_SERIO_RAW is not set CONFIG_SERIO_SERPORT=y -CONFIG_SERIO=y # CONFIG_SGI_IP22 is not set # CONFIG_SGI_IP27 is not set # CONFIG_SGI_IP28 is not set @@ -241,9 +241,9 @@ CONFIG_TMPFS_POSIX_ACL=y CONFIG_TRAD_SIGNALS=y # CONFIG_TREE_PREEMPT_RCU is not set CONFIG_TREE_RCU=y +CONFIG_USB=m CONFIG_USB_ADM5120_HCD=m CONFIG_USB_EHCI_HCD=m -CONFIG_USB=m # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set CONFIG_USB_OHCI_HCD=m diff --git a/target/linux/ar7/patches-2.6.32/100-board_support.patch b/target/linux/ar7/patches-2.6.32/100-board_support.patch new file mode 100644 index 000000000..caa441eaf --- /dev/null +++ b/target/linux/ar7/patches-2.6.32/100-board_support.patch @@ -0,0 +1,28 @@ +--- a/arch/mips/kernel/traps.c ++++ b/arch/mips/kernel/traps.c +@@ -1256,9 +1256,22 @@ void *set_except_vector(int n, void *add + + exception_handlers[n] = handler; + if (n == 0 && cpu_has_divec) { +- *(u32 *)(ebase + 0x200) = 0x08000000 | +- (0x03ffffff & (handler >> 2)); +- local_flush_icache_range(ebase + 0x200, ebase + 0x204); ++ if ((handler ^ (ebase + 4)) & 0xfc000000) { ++ /* lui k0, 0x0000 */ ++ *(u32 *)(ebase + 0x200) = 0x3c1a0000 | (handler >> 16); ++ /* ori k0, 0x0000 */ ++ *(u32 *)(ebase + 0x204) = ++ 0x375a0000 | (handler & 0xffff); ++ /* jr k0 */ ++ *(u32 *)(ebase + 0x208) = 0x03400008; ++ /* nop */ ++ *(u32 *)(ebase + 0x20C) = 0x00000000; ++ flush_icache_range(ebase + 0x200, ebase + 0x210); ++ } else { ++ *(u32 *)(ebase + 0x200) = ++ 0x08000000 | (0x03ffffff & (handler >> 2)); ++ flush_icache_range(ebase + 0x200, ebase + 0x204); ++ } + } + return (void *)old_handler; + } diff --git a/target/linux/ar71xx/base-files/etc/defconfig/tl-wr1043nd/network b/target/linux/ar71xx/base-files/etc/defconfig/tl-wr1043nd/network new file mode 100644 index 000000000..7e710f229 --- /dev/null +++ b/target/linux/ar71xx/base-files/etc/defconfig/tl-wr1043nd/network @@ -0,0 +1,31 @@ +config 'interface' 'loopback' + option 'ifname' 'lo' + option 'proto' 'static' + option 'ipaddr' '127.0.0.1' + option 'netmask' '255.0.0.0' + +config 'interface' 'lan' + option 'ifname' 'eth0.1' + option 'type' 'bridge' + option 'proto' 'static' + option 'ipaddr' '192.168.1.1' + option 'netmask' '255.255.255.0' + +config 'interface' 'wan' + option 'ifname' 'eth0.2' + option 'proto' 'dhcp' + +config 'switch' + option 'name' 'rtl8366rb' + option 'reset' '1' + option 'enable_vlan' '1' + +config 'switch_vlan' + option 'device' 'rtl8366rb' + option 'vlan' '1' + option 'ports' '1 2 3 4 5t' + +config 'switch_vlan' + option 'device' 'rtl8366rb' + option 'vlan' '2' + option 'ports' '0 5t' diff --git a/target/linux/ar71xx/base-files/etc/defconfig/wndr3700/network b/target/linux/ar71xx/base-files/etc/defconfig/wndr3700/network index 3ab4bc81d..5aba76cf6 100644 --- a/target/linux/ar71xx/base-files/etc/defconfig/wndr3700/network +++ b/target/linux/ar71xx/base-files/etc/defconfig/wndr3700/network @@ -19,8 +19,53 @@ config switch option name rtl8366s option reset 1 option enable_vlan 1 + # Blinkrate: 0=43ms; 1=84ms; 2=120ms; 3=170ms; 4=340ms; 5=670ms + option blinkrate 2 config switch_vlan option device rtl8366s option vlan 0 option ports "0 1 2 3 5" + +config switch_port + # Port 1 controls the GREEN configuration of LEDs for + # the switch and the section does not correspond to a real + # switch port. + # + # 0=LED off; 1=Collision/FDX; 2=Link/activity; 3-1000MB/s + # 4=100 MB/s; 5=10 MB/s; 6=1000 MB/s+activity; 7=100 MB/s+activity + # 8=10 MB/s+activity; 9=10/100 Mb/s+activity; 10: Fiber; + # 11: Fault; 12: Link/activity(tx); 13: Link/activity(rx); + # 14: Link (master); 15: separate register + + option device rtl8366s + option port 1 + option led 9 + +config switch_port + # Port 2 controls the ORANGE configuration of LEDs for + # the switch and the section does not correspond to a real + # switch port. + # + # See the key above for switch port 1 for the meaning of the + # 'led' setting below. + + option device rtl8366s + option port 2 + option led 6 + + +config switch_port + # Port 5 controls the configuration of the WAN LED and the + # section does not correspond to a real switch port. + # + # To toggle the use of green or orange LEDs for the WAN port, + # see the LED setting for wndr3700:green:wan in /etc/config/system. + # + # See the key above for switch port 1 for the meaning of the + # 'led' setting below. + + option device rtl8366s + option port 5 + option led 6 + diff --git a/target/linux/ar71xx/base-files/etc/diag.sh b/target/linux/ar71xx/base-files/etc/diag.sh index 2a6af7da2..0b8d9a73c 100755 --- a/target/linux/ar71xx/base-files/etc/diag.sh +++ b/target/linux/ar71xx/base-files/etc/diag.sh @@ -91,7 +91,7 @@ get_status_led() { status_led="wp543:green:diag" ;; wrt400n) - status_led="wrt400n:blue:status" + status_led="wrt400n:green:status" ;; wrt160nl) status_led="wrt160nl:blue:wps" diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/wndr3700 b/target/linux/ar71xx/base-files/etc/uci-defaults/wndr3700 new file mode 100755 index 000000000..91f282b77 --- /dev/null +++ b/target/linux/ar71xx/base-files/etc/uci-defaults/wndr3700 @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Copyright (C) 2010 OpenWrt.org +# + +. /lib/ar71xx.sh + +board=$(ar71xx_board_name) + +wndr3700_set_wan_led() { + uci batch < + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include "devices.h" + +void __init ap91_eth_init(u8 *mac_addr) +{ + if (mac_addr) + ar71xx_set_mac_base(mac_addr); + + /* WAN port */ + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth0_data.phy_mask = 0x0; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + ar71xx_eth0_data.fifo_cfg1 = 0x0fff0000; + ar71xx_eth0_data.fifo_cfg2 = 0x00001fff; + ar71xx_eth0_data.fifo_cfg3 = 0x008001ff; + + /* LAN ports */ + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.phy_mask = 0x0; + ar71xx_eth1_data.speed = SPEED_1000; + ar71xx_eth1_data.duplex = DUPLEX_FULL; + ar71xx_eth1_data.fifo_cfg1 = 0x0fff0000; + ar71xx_eth1_data.fifo_cfg2 = 0x00001fff; + ar71xx_eth1_data.fifo_cfg3 = 0x008001ff; + + ar71xx_add_device_mdio(0x0); + ar71xx_add_device_eth(1); + ar71xx_add_device_eth(0); +} diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/dev-ap91-eth.h b/target/linux/ar71xx/files/arch/mips/ar71xx/dev-ap91-eth.h new file mode 100644 index 000000000..424e2ae46 --- /dev/null +++ b/target/linux/ar71xx/files/arch/mips/ar71xx/dev-ap91-eth.h @@ -0,0 +1,21 @@ +/* + * Atheros AP91 reference board ethernet initialization + * + * Copyright (C) 2010 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef _AR71XX_DEV_AP91_ETH_H +#define _AR71XX_DEV_AP91_ETH_H + +#if defined(CONFIG_AR71XX_DEV_AP91_ETH) +void ap91_eth_init(u8 *mac_addr) __init; +#else +static inline void ap91_eth_init(u8 *mac_addr) { } +#endif + +#endif /* _AR71XX_DEV_AP91_ETH_H */ + diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-dir-600-a1.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-dir-600-a1.c index 68f182268..42146f55c 100644 --- a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-dir-600-a1.c +++ b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-dir-600-a1.c @@ -16,9 +16,11 @@ #include "machtype.h" #include "devices.h" #include "dev-m25p80.h" +#include "dev-ap91-eth.h" #include "dev-ap91-pci.h" #include "dev-gpio-buttons.h" #include "dev-leds-gpio.h" +#include "nvram.h" #define DIR_600_A1_GPIO_LED_WPS 0 #define DIR_600_A1_GPIO_LED_POWER_AMBER 1 @@ -29,6 +31,9 @@ #define DIR_600_A1_BUTTONS_POLL_INTERVAL 20 +#define DIR_600_A1_NVRAM_ADDR 0x1f030000 +#define DIR_600_A1_NVRAM_SIZE 0x10000 + #ifdef CONFIG_MTD_PARTITIONS static struct mtd_partition dir_600_a1_partitions[] = { { @@ -107,32 +112,14 @@ static struct gpio_button dir_600_a1_gpio_buttons[] __initdata = { static void __init dir_600_a1_setup(void) { - u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000); + const char *nvram = (char *) KSEG1ADDR(DIR_600_A1_NVRAM_ADDR); u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000); + u8 mac_buff[6]; + u8 *mac = NULL; - ar71xx_set_mac_base(mac); - ar71xx_add_device_mdio(0x0); - - /* WAN port */ - ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; - ar71xx_eth0_data.phy_mask = 0x0; - ar71xx_eth0_data.speed = SPEED_100; - ar71xx_eth0_data.duplex = DUPLEX_FULL; - ar71xx_eth0_data.fifo_cfg1 = 0x0fff0000; - ar71xx_eth0_data.fifo_cfg2 = 0x00001fff; - ar71xx_eth0_data.fifo_cfg3 = 0x008001ff; - - /* LAN ports */ - ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; - ar71xx_eth1_data.phy_mask = 0x0; - ar71xx_eth1_data.speed = SPEED_1000; - ar71xx_eth1_data.duplex = DUPLEX_FULL; - ar71xx_eth1_data.fifo_cfg1 = 0x0fff0000; - ar71xx_eth1_data.fifo_cfg2 = 0x00001fff; - ar71xx_eth1_data.fifo_cfg3 = 0x008001ff; - - ar71xx_add_device_eth(1); - ar71xx_add_device_eth(0); + if (nvram_parse_mac_addr(nvram, DIR_600_A1_NVRAM_SIZE, + "lan_mac=", mac_buff) == 0) + mac = mac_buff; ar71xx_add_device_m25p80(&dir_600_a1_flash_data); @@ -143,7 +130,8 @@ static void __init dir_600_a1_setup(void) ARRAY_SIZE(dir_600_a1_gpio_buttons), dir_600_a1_gpio_buttons); - ap91_pci_init(ee, NULL); + ap91_eth_init(mac); + ap91_pci_init(ee, mac); } MIPS_MACHINE(AR71XX_MACH_DIR_600_A1, "DIR-600-A1", "D-Link DIR-600 rev. A1", diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-tl-wr1043nd.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-tl-wr1043nd.c index 985b9f249..fd8e5fce8 100644 --- a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-tl-wr1043nd.c +++ b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-tl-wr1043nd.c @@ -10,7 +10,8 @@ #include #include - +#include +#include #include #include "machtype.h" @@ -29,6 +30,9 @@ #define TL_WR1043ND_GPIO_BTN_RESET 3 #define TL_WR1043ND_GPIO_BTN_QSS 7 +#define TL_WR1043ND_GPIO_RTL8366_SDA 18 +#define TL_WR1043ND_GPIO_RTL8366_SCK 19 + #define TL_WR1043ND_BUTTONS_POLL_INTERVAL 20 #ifdef CONFIG_MTD_PARTITIONS @@ -104,6 +108,19 @@ static struct gpio_button tl_wr1043nd_gpio_buttons[] __initdata = { } }; +static struct rtl8366rb_platform_data tl_wr1043nd_rtl8366rb_data = { + .gpio_sda = TL_WR1043ND_GPIO_RTL8366_SDA, + .gpio_sck = TL_WR1043ND_GPIO_RTL8366_SCK, +}; + +static struct platform_device tl_wr1043nd_rtl8366rb_device = { + .name = RTL8366RB_DRIVER_NAME, + .id = -1, + .dev = { + .platform_data = &tl_wr1043nd_rtl8366rb_data, + } +}; + static void __init tl_wr1043nd_setup(void) { u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00); @@ -111,12 +128,12 @@ static void __init tl_wr1043nd_setup(void) ar71xx_set_mac_base(mac); - ar71xx_add_device_mdio(0x0); - + ar71xx_eth0_data.mii_bus_dev = &tl_wr1043nd_rtl8366rb_device.dev; ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; ar71xx_eth0_data.phy_mask = 0x0; ar71xx_eth0_data.speed = SPEED_1000; ar71xx_eth0_data.duplex = DUPLEX_FULL; + ar71xx_eth0_pll_data.pll_1000 = 0x1a000000; ar71xx_add_device_eth(0); @@ -127,9 +144,12 @@ static void __init tl_wr1043nd_setup(void) ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr1043nd_leds_gpio), tl_wr1043nd_leds_gpio); + platform_device_register(&tl_wr1043nd_rtl8366rb_device); + ar71xx_add_device_gpio_buttons(-1, TL_WR1043ND_BUTTONS_POLL_INTERVAL, ARRAY_SIZE(tl_wr1043nd_gpio_buttons), tl_wr1043nd_gpio_buttons); + ar913x_add_device_wmac(eeprom, mac); } diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-tl-wr741nd.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-tl-wr741nd.c index e5d977639..f6f305982 100644 --- a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-tl-wr741nd.c +++ b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-tl-wr741nd.c @@ -1,7 +1,7 @@ /* * TP-LINK TL-WR741ND board support * - * Copyright (C) 2009 Gabor Juhos + * Copyright (C) 2009-2010 Gabor Juhos * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -16,6 +16,7 @@ #include "machtype.h" #include "devices.h" #include "dev-m25p80.h" +#include "dev-ap91-eth.h" #include "dev-ap91-pci.h" #include "dev-gpio-buttons.h" #include "dev-leds-gpio.h" @@ -98,30 +99,6 @@ static void __init tl_wr741nd_setup(void) u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00); u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000); - ar71xx_set_mac_base(mac); - ar71xx_add_device_mdio(0x0); - - /* WAN port */ - ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; - ar71xx_eth0_data.phy_mask = 0x0; - ar71xx_eth0_data.speed = SPEED_100; - ar71xx_eth0_data.duplex = DUPLEX_FULL; - ar71xx_eth0_data.fifo_cfg1 = 0x0fff0000; - ar71xx_eth0_data.fifo_cfg2 = 0x00001fff; - ar71xx_eth0_data.fifo_cfg3 = 0x008001ff; - - /* LAN ports */ - ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; - ar71xx_eth1_data.phy_mask = 0x0; - ar71xx_eth1_data.speed = SPEED_1000; - ar71xx_eth1_data.duplex = DUPLEX_FULL; - ar71xx_eth1_data.fifo_cfg1 = 0x0fff0000; - ar71xx_eth1_data.fifo_cfg2 = 0x00001fff; - ar71xx_eth1_data.fifo_cfg3 = 0x008001ff; - - ar71xx_add_device_eth(1); - ar71xx_add_device_eth(0); - ar71xx_add_device_m25p80(&tl_wr741nd_flash_data); ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr741nd_leds_gpio), @@ -131,7 +108,8 @@ static void __init tl_wr741nd_setup(void) ARRAY_SIZE(tl_wr741nd_gpio_buttons), tl_wr741nd_gpio_buttons); - ap91_pci_init(ee, NULL); + ap91_eth_init(mac); + ap91_pci_init(ee, mac); } MIPS_MACHINE(AR71XX_MACH_TL_WR741ND, "TL-WR741ND", "TP-LINK TL-WR741ND", tl_wr741nd_setup); diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-wndr3700.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-wndr3700.c index eaa9654aa..3dd97789a 100644 --- a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-wndr3700.c +++ b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-wndr3700.c @@ -29,6 +29,7 @@ #define WNDR3700_GPIO_LED_POWER_ORANGE 1 #define WNDR3700_GPIO_LED_POWER_GREEN 2 #define WNDR3700_GPIO_LED_WPS_GREEN 4 +#define WNDR3700_GPIO_LED_WAN_GREEN 6 #define WNDR3700_GPIO_BTN_WPS 3 #define WNDR3700_GPIO_BTN_RESET 8 @@ -118,6 +119,10 @@ static struct gpio_led wndr3700_leds_gpio[] __initdata = { .name = "wndr3700:orange:wps", .gpio = WNDR3700_GPIO_LED_WPS_ORANGE, .active_low = 1, + }, { + .name = "wndr3700:green:wan", + .gpio = WNDR3700_GPIO_LED_WAN_GREEN, + .active_low = 1, } }; @@ -128,18 +133,21 @@ static struct gpio_button wndr3700_gpio_buttons[] __initdata = { .code = BTN_0, .threshold = 3, .gpio = WNDR3700_GPIO_BTN_RESET, + .active_low = 1, }, { .desc = "wps", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = WNDR3700_GPIO_BTN_WPS, + .active_low = 1, } , { .desc = "wifi", .type = EV_KEY, .code = BTN_2, .threshold = 3, .gpio = WNDR3700_GPIO_BTN_WIFI, + .active_low = 1, } }; diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c index 884366fd3..64b5cc8e0 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c @@ -390,7 +390,12 @@ static void ag71xx_hw_init(struct ag71xx *ag) mdelay(100); /* setup MAC configuration registers */ - ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT); + if (pdata->is_ar724x) + ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, + MAC_CFG1_INIT | MAC_CFG1_TFC | MAC_CFG1_RFC); + else + ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT); + ag71xx_sb(ag, AG71XX_REG_MAC_CFG2, MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK); diff --git a/target/linux/ar71xx/image/Makefile b/target/linux/ar71xx/image/Makefile index f5bafdb90..c7d4fc147 100644 --- a/target/linux/ar71xx/image/Makefile +++ b/target/linux/ar71xx/image/Makefile @@ -488,6 +488,10 @@ define Image/Build/Profile/TLWR941NDV2 $(call Image/Build/Template/$(fs_squash)/$(1),TPLINK,tl-wr941nd-v2,board=TL-WR941ND,TL-WR941NDv2) endef +define Image/Build/Profile/TLWR941NDV4 + $(call Image/Build/Template/$(fs_4k)/$(1),TPLINK,tl-wr941nd-v4,board=TL-WR741ND,TL-WR941NDv4) +endef + define Image/Build/Profile/TLWR1043NDV1 $(call Image/Build/Template/$(fs_squash)/$(1),TPLINK,tl-wr1043nd-v1,board=TL-WR1043ND,TL-WR1043NDv1) endef @@ -530,6 +534,7 @@ define Image/Build/Profile/Default $(call Image/Build/Profile/TLWR841NDV3,$(1)) $(call Image/Build/Profile/TLWR841NDV5,$(1)) $(call Image/Build/Profile/TLWR941NDV2,$(1)) + $(call Image/Build/Profile/TLWR941NDV4,$(1)) $(call Image/Build/Profile/TLWR1043NDV1,$(1)) $(call Image/Build/Profile/UBNT,$(1)) $(call Image/Build/Profile/WP543,$(1)) diff --git a/target/linux/ar71xx/patches-2.6.32/101-ksz8041_phy_driver.patch b/target/linux/ar71xx/patches-2.6.32/101-ksz8041_phy_driver.patch index 94193e855..503604610 100644 --- a/target/linux/ar71xx/patches-2.6.32/101-ksz8041_phy_driver.patch +++ b/target/linux/ar71xx/patches-2.6.32/101-ksz8041_phy_driver.patch @@ -14,9 +14,9 @@ depends on PHYLIB=y --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile -@@ -23,6 +23,7 @@ obj-$(CONFIG_RTL8306_PHY) += rtl8306.o - obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o +@@ -24,6 +24,7 @@ obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o + obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o +obj-$(CONFIG_MICREL) += micrel.o obj-$(CONFIG_FIXED_PHY) += fixed.o diff --git a/target/linux/ar71xx/patches-2.6.32/960-ar8216-add-register-debug.patch b/target/linux/ar71xx/patches-2.6.32/960-ar8216-add-register-debug.patch deleted file mode 100644 index f4d1e586e..000000000 --- a/target/linux/ar71xx/patches-2.6.32/960-ar8216-add-register-debug.patch +++ /dev/null @@ -1,257 +0,0 @@ ---- a/drivers/net/phy/ar8216.c -+++ b/drivers/net/phy/ar8216.c -@@ -563,10 +563,227 @@ ar8216_config_aneg(struct phy_device *ph - return 0; - } - -+#define ar8216_dbg(fmt, args...) printk(KERN_DEBUG "ar8216: " fmt, ## args) -+ -+static inline const char *ctrl_state_str(u32 ctrl) -+{ -+ switch (ctrl & AR8216_PORT_CTRL_STATE) { -+ case AR8216_PORT_STATE_DISABLED: -+ return "disabled"; -+ case AR8216_PORT_STATE_BLOCK: -+ return "block"; -+ case AR8216_PORT_STATE_LISTEN: -+ return "listen"; -+ case AR8216_PORT_STATE_LEARN: -+ return "learn"; -+ case AR8216_PORT_STATE_FORWARD: -+ return "forward"; -+ default: -+ break; -+ } -+ -+ return "????"; -+} -+ -+static inline const char *ctrl_vlanmode_str(u32 ctrl) -+{ -+ u32 vlan_mode; -+ -+ vlan_mode = (ctrl & AR8216_PORT_CTRL_VLAN_MODE) >> -+ AR8216_PORT_CTRL_VLAN_MODE_S; -+ switch (vlan_mode) { -+ case AR8216_OUT_KEEP: -+ return "keep"; -+ case AR8216_OUT_STRIP_VLAN: -+ return "strip vlan"; -+ case AR8216_OUT_ADD_VLAN: -+ return "add_vlan"; -+ default: -+ break; -+ } -+ -+ return "????"; -+} -+ -+static inline const char *vlan_vlanmode_str(u32 vlan) -+{ -+ u32 vlan_mode; -+ -+ vlan_mode = (vlan & AR8216_PORT_VLAN_MODE) >> -+ AR8216_PORT_VLAN_MODE_S; -+ switch (vlan_mode) { -+ case AR8216_IN_PORT_ONLY: -+ return "port only"; -+ case AR8216_IN_PORT_FALLBACK: -+ return "port fallback"; -+ case AR8216_IN_VLAN_ONLY: -+ return "VLAN only"; -+ case AR8216_IN_SECURE: -+ return "secure"; -+ default: -+ break; -+ } -+ -+ return "????"; -+} -+ -+static void -+ar8216_dump_regs(struct ar8216_priv *ap) -+{ -+ unsigned int i; -+ u32 t; -+ -+ t = ar8216_mii_read(ap, AR8216_REG_CTRL); -+ ar8216_dbg("CTRL\t\t: %08x\n", t); -+ ar8216_dbg(" version\t: %u\n", (t & 0xff00) >> 8); -+ ar8216_dbg(" revision\t: %u\n", (t & 0xff)); -+ -+ ar8216_dbg("POWER_ON\t: %08x\n", -+ ar8216_mii_read(ap, 0x04)); -+ ar8216_dbg("INT\t\t: %08x\n", -+ ar8216_mii_read(ap, 0x10)); -+ ar8216_dbg("INT_MASK\t: %08x\n", -+ ar8216_mii_read(ap, 0x14)); -+ ar8216_dbg("MAC_ADDR0\t: %08x\n", -+ ar8216_mii_read(ap, 0x20)); -+ ar8216_dbg("MAC_ADDR1\t: %08x\n", -+ ar8216_mii_read(ap, 0x24)); -+ ar8216_dbg("FLOOD_MASK\t: %08x\n", -+ ar8216_mii_read(ap, 0x2c)); -+ -+ t = ar8216_mii_read(ap, AR8216_REG_GLOBAL_CTRL); -+ ar8216_dbg("GLOBAL_CTRL\t: %08x\n", t); -+ ar8216_dbg(" mtu\t\t: %lu\n", t & AR8216_GCTRL_MTU); -+ -+ ar8216_dbg("FLOW_CONTROL0\t: %08x\n", -+ ar8216_mii_read(ap, 0x34)); -+ ar8216_dbg("FLOW_CONTROL1\t: %08x\n", -+ ar8216_mii_read(ap, 0x38)); -+ ar8216_dbg("QM_CONTROL\t: %08x\n", -+ ar8216_mii_read(ap, 0x3c)); -+ ar8216_dbg("VLAN_TABLE0\t: %08x\n", -+ ar8216_mii_read(ap, AR8216_REG_VTU)); -+ ar8216_dbg("VLAN_TABLE1\t: %08x\n", -+ ar8216_mii_read(ap, AR8216_REG_VTU_DATA)); -+ ar8216_dbg("ADDR_TABLE0\t: %08x\n", -+ ar8216_mii_read(ap, AR8216_REG_ATU)); -+ ar8216_dbg("ADDR_TABLE1\t: %08x\n", -+ ar8216_mii_read(ap, AR8216_REG_ATU_DATA)); -+ ar8216_dbg("ADDR_TABLE2\t: %08x\n", -+ ar8216_mii_read(ap, 0x58)); -+ ar8216_dbg("ADDR_CTRL\t: %08x\n", -+ ar8216_mii_read(ap, 0x5c)); -+ ar8216_dbg("IP_PRIO0\t: %08x\n", -+ ar8216_mii_read(ap, 0x60)); -+ ar8216_dbg("IP_PRIO1\t: %08x\n", -+ ar8216_mii_read(ap, 0x64)); -+ ar8216_dbg("IP_PRIO2\t: %08x\n", -+ ar8216_mii_read(ap, 0x68)); -+ ar8216_dbg("IP_PRIO3\t: %08x\n", -+ ar8216_mii_read(ap, 0x6c)); -+ ar8216_dbg("TAG_PRIO\t: %08x\n", -+ ar8216_mii_read(ap, 0x70)); -+ ar8216_dbg("SERVICE_TAG\t: %08x\n", -+ ar8216_mii_read(ap, 0x74)); -+ ar8216_dbg("CPU_PORT\t: %08x\n", -+ ar8216_mii_read(ap, 0x78)); -+ ar8216_dbg("MIB_FUNC\t: %08x\n", -+ ar8216_mii_read(ap, 0x80)); -+ ar8216_dbg("MDIO\t\t: %08x\n", -+ ar8216_mii_read(ap, 0x98)); -+ ar8216_dbg("LED0\t\t: %08x\n", -+ ar8216_mii_read(ap, 0xb0)); -+ ar8216_dbg("LED1\t\t: %08x\n", -+ ar8216_mii_read(ap, 0xb4)); -+ ar8216_dbg("LED2\t\t: %08x\n", -+ ar8216_mii_read(ap, 0xb8)); -+ -+ for (i = 0; i < 6; i++) { -+ u32 reg = 0x100 * (i + 1); -+ -+ t = ar8216_mii_read(ap, AR8216_REG_PORT_STATUS(i)); -+ ar8216_dbg("PORT%d_STATUS\t: %08x\n", i, t); -+ ar8216_dbg(" speed\t\t: %s\n", -+ (t & AR8216_PORT_STATUS_SPEED) ? "100" : "10"); -+ ar8216_dbg(" speed error\t: %s\n", -+ (t & AR8216_PORT_STATUS_SPEED_ERR) ? "yes" : "no"); -+ ar8216_dbg(" txmac\t\t: %d\n", -+ (t & AR8216_PORT_STATUS_TXMAC) ? 1 : 0); -+ ar8216_dbg(" rxmac\t\t: %d\n", -+ (t & AR8216_PORT_STATUS_RXMAC) ? 1 : 0); -+ ar8216_dbg(" tx_flow\t: %s\n", -+ (t & AR8216_PORT_STATUS_TXFLOW) ? "on" : "off"); -+ ar8216_dbg(" rx_flow\t: %s\n", -+ (t & AR8216_PORT_STATUS_RXFLOW) ? "on" : "off"); -+ ar8216_dbg(" duplex\t: %s\n", -+ (t & AR8216_PORT_STATUS_DUPLEX) ? "full" : "half"); -+ ar8216_dbg(" link\t\t: %s\n", -+ (t & AR8216_PORT_STATUS_LINK_UP) ? "up" : "down"); -+ ar8216_dbg(" auto\t\t: %s\n", -+ (t & AR8216_PORT_STATUS_LINK_AUTO) ? "on" : "off"); -+ ar8216_dbg(" pause\t\t: %s\n", -+ (t & AR8216_PORT_STATUS_LINK_PAUSE) ? "on" : "off"); -+ -+ t = ar8216_mii_read(ap, AR8216_REG_PORT_CTRL(i)); -+ ar8216_dbg("PORT%d_CTRL\t: %08x\n", i, t); -+ ar8216_dbg(" state\t\t: %s\n", ctrl_state_str(t)); -+ ar8216_dbg(" learn lock\t: %s\n", -+ (t & AR8216_PORT_CTRL_LEARN_LOCK) ? "on" : "off"); -+ ar8216_dbg(" vlan_mode\t: %s\n", ctrl_vlanmode_str(t)); -+ ar8216_dbg(" igmp_snoop\t: %s\n", -+ (t & AR8216_PORT_CTRL_IGMP_SNOOP) ? "on" : "off"); -+ ar8216_dbg(" header\t: %s\n", -+ (t & AR8216_PORT_CTRL_HEADER) ? "on" : "off"); -+ ar8216_dbg(" mac_loop\t: %s\n", -+ (t & AR8216_PORT_CTRL_MAC_LOOP) ? "on" : "off"); -+ ar8216_dbg(" single_vlan\t: %s\n", -+ (t & AR8216_PORT_CTRL_SINGLE_VLAN) ? "on" : "off"); -+ ar8216_dbg(" mirror tx\t: %s\n", -+ (t & AR8216_PORT_CTRL_MIRROR_TX) ? "on" : "off"); -+ ar8216_dbg(" mirror rx\t: %s\n", -+ (t & AR8216_PORT_CTRL_MIRROR_RX) ? "on" : "off"); -+ -+ t = ar8216_mii_read(ap, AR8216_REG_PORT_VLAN(i)); -+ ar8216_dbg("PORT%d_VLAN\t: %08x\n", i, t); -+ ar8216_dbg(" default id\t: %lu\n", -+ (t & AR8216_PORT_VLAN_DEFAULT_ID)); -+ ar8216_dbg(" dest ports\t: %s%s%s%s%s%s\n", -+ (t & 0x010000) ? "0 " : "", -+ (t & 0x020000) ? "1 " : "", -+ (t & 0x040000) ? "2 " : "", -+ (t & 0x080000) ? "3 " : "", -+ (t & 0x100000) ? "4 " : "", -+ (t & 0x200000) ? "5 " : ""); -+ ar8216_dbg(" tx priority\t: %s\n", -+ (t & AR8216_PORT_VLAN_TX_PRIO) ? "on" : "off"); -+ ar8216_dbg(" port priority\t: %lu\n", -+ (t & AR8216_PORT_VLAN_PRIORITY) >> -+ AR8216_PORT_VLAN_PRIORITY_S); -+ ar8216_dbg(" ingress mode\t: %s\n", vlan_vlanmode_str(t)); -+ -+ t = ar8216_mii_read(ap, AR8216_REG_PORT_RATE(i)); -+ ar8216_dbg("PORT%d_RATE0\t: %08x\n", i, t); -+ -+ ar8216_dbg("PORT%d_PRIO\t: %08x\n", i, -+ ar8216_mii_read(ap, AR8216_REG_PORT_PRIO(i))); -+ ar8216_dbg("PORT%d_STORM\t: %08x\n", i, -+ ar8216_mii_read(ap, reg + 0x14)); -+ ar8216_dbg("PORT%d_QUEUE\t: %08x\n", i, -+ ar8216_mii_read(ap, reg + 0x18)); -+ ar8216_dbg("PORT%d_RATE1\t: %08x\n", i, -+ ar8216_mii_read(ap, reg + 0x1c)); -+ ar8216_dbg("PORT%d_RATE2\t: %08x\n", i, -+ ar8216_mii_read(ap, reg + 0x20)); -+ ar8216_dbg("PORT%d_RATE3\t: %08x\n", i, -+ ar8216_mii_read(ap, reg + 0x24)); -+ } -+} -+ - static int - ar8216_probe(struct phy_device *pdev) - { - struct ar8216_priv priv; -+ static int regs_dumped; - - u8 id, rev; - u32 val; -@@ -575,9 +792,14 @@ ar8216_probe(struct phy_device *pdev) - val = ar8216_mii_read(&priv, AR8216_REG_CTRL); - rev = val & 0xff; - id = (val >> 8) & 0xff; -- if ((id != 1) || (rev != 1)) -+ if ((id != 1) || (rev != 1 && rev != 2)) - return -ENODEV; - -+ if (!regs_dumped) { -+ ar8216_dump_regs(&priv); -+ regs_dumped++; -+ } -+ - return 0; - } - ---- a/drivers/net/phy/ar8216.h -+++ b/drivers/net/phy/ar8216.h -@@ -27,7 +27,7 @@ - #define AR8216_CTRL_RESET BIT(31) - - #define AR8216_REG_GLOBAL_CTRL 0x0030 --#define AR8216_GCTRL_MTU BITS(0, 10) -+#define AR8216_GCTRL_MTU BITS(0, 12) - - #define AR8216_REG_VTU 0x0040 - #define AR8216_VTU_OP BITS(0, 3) diff --git a/target/linux/ar71xx/profiles/atheros.mk b/target/linux/ar71xx/profiles/atheros.mk index c80931142..a7ed71414 100644 --- a/target/linux/ar71xx/profiles/atheros.mk +++ b/target/linux/ar71xx/profiles/atheros.mk @@ -18,7 +18,8 @@ $(eval $(call Profile,AP81)) define Profile/AP83 NAME:=Atheros AP83 reference board - PACKAGES:=wpad-mini kmod-ath9k kmod-usb-core kmod-usb2 + PACKAGES:=wpad-mini kmod-ath9k kmod-usb-core kmod-usb2 \ + vsc7385-ucode-ap83 vsc7395-ucode-ap83 endef define Profile/AP83/Description @@ -40,7 +41,8 @@ $(eval $(call Profile,PB42)) define Profile/PB44 NAME:=Atheros PB44 reference board - PACKAGES:=wpad-mini kmod-ath9k kmod-usb-core kmod-usb-ohci kmod-usb2 + PACKAGES:=wpad-mini kmod-ath9k kmod-usb-core kmod-usb-ohci kmod-usb2 \ + vsc7385-ucode-pb44 vsc7395-ucode-pb44 endef define Profile/PB44/Description diff --git a/target/linux/ar71xx/profiles/tp-link.mk b/target/linux/ar71xx/profiles/tp-link.mk index 09fbcc9e7..ffb3b9e06 100644 --- a/target/linux/ar71xx/profiles/tp-link.mk +++ b/target/linux/ar71xx/profiles/tp-link.mk @@ -60,6 +60,17 @@ endef $(eval $(call Profile,TLWR941NDV2)) +define Profile/TLWR941NDV4 + NAME:=TP-LINK TL-WR941ND v4 + PACKAGES:=kmod-ath9k wpad-mini +endef + +define Profile/TLWR941NDV4/Description + Package set optimized for the TP-LINK TL-WR941ND v4. +endef + +$(eval $(call Profile,TLWR941NDV4)) + define Profile/TLWR1043NDV1 NAME:=TP-LINK TL-WR1043ND v1 PACKAGES:=kmod-ath9k wpad-mini kmod-usb-core kmod-usb2 diff --git a/target/linux/at91/config-2.6.25 b/target/linux/at91/config-2.6.25 index 196f2d104..572d59611 100644 --- a/target/linux/at91/config-2.6.25 +++ b/target/linux/at91/config-2.6.25 @@ -133,10 +133,6 @@ CONFIG_MTD_CMDLINE_PARTS=y # CONFIG_PCI is not set # CONFIG_PCI_SYSCALL is not set CONFIG_PHYLIB=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPPOATM is not set -# CONFIG_PPPOL2TP is not set -# CONFIG_PPP_SYNC_TTY is not set # CONFIG_SCSI_WAIT_SCAN is not set # CONFIG_SDIO_UART is not set # CONFIG_SERIAL_8250 is not set diff --git a/target/linux/au1000/Makefile b/target/linux/au1000/Makefile index e9351c7f2..9a171cfe1 100644 --- a/target/linux/au1000/Makefile +++ b/target/linux/au1000/Makefile @@ -12,7 +12,7 @@ BOARDNAME:=RMI/AMD AU1x00 FEATURES:=jffs2 usb pci SUBTARGETS=au1500 au1550 -LINUX_VERSION:=2.6.30.10 +LINUX_VERSION:=2.6.32.8 include $(INCLUDE_DIR)/target.mk DEFAULT_PACKAGES += wpad-mini yamonenv diff --git a/target/linux/au1000/au1500/config-2.6.32 b/target/linux/au1000/au1500/config-2.6.32 index 2b81ee000..998a3f8f2 100644 --- a/target/linux/au1000/au1500/config-2.6.32 +++ b/target/linux/au1000/au1500/config-2.6.32 @@ -26,9 +26,9 @@ CONFIG_CPU_HAS_PREFETCH=y CONFIG_CPU_HAS_SYNC=y CONFIG_CPU_LITTLE_ENDIAN=y # CONFIG_CPU_LOONGSON2E is not set +CONFIG_CPU_MIPS32=y CONFIG_CPU_MIPS32_R1=y # CONFIG_CPU_MIPS32_R2 is not set -CONFIG_CPU_MIPS32=y # CONFIG_CPU_MIPS64_R1 is not set # CONFIG_CPU_MIPS64_R2 is not set CONFIG_CPU_MIPSR1=y @@ -62,14 +62,15 @@ CONFIG_DMA_NONCOHERENT=y CONFIG_DUMMY=m CONFIG_ELF_CORE=y # CONFIG_FSNOTIFY is not set -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_FIND_LAST_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_GPIO=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y # CONFIG_HAMRADIO is not set CONFIG_HARDWARE_WATCHPOINTS=y CONFIG_HAS_DMA=y @@ -81,15 +82,15 @@ CONFIG_HAVE_IDE=y CONFIG_HAVE_OPROFILE=y CONFIG_HW_HAS_PCI=y CONFIG_HW_RANDOM=y -# CONFIG_HZ_100 is not set CONFIG_HZ=250 +# CONFIG_HZ_100 is not set CONFIG_HZ_250=y +CONFIG_I2C=m CONFIG_I2C_ALGOBIT=m CONFIG_I2C_ALGOPCA=m CONFIG_I2C_ALGOPCF=m CONFIG_I2C_BOARDINFO=y CONFIG_I2C_CHARDEV=m -CONFIG_I2C=m CONFIG_INITRAMFS_SOURCE="" CONFIG_IRQ_CPU=y CONFIG_KEXEC=y @@ -103,6 +104,7 @@ CONFIG_MACH_ALCHEMY=y # CONFIG_MACH_VR41XX is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_MIKROTIK_RB532 is not set +CONFIG_MIPS=y CONFIG_MIPS_AU1X00_ENET=y # CONFIG_MIPS_BOSPORUS is not set # CONFIG_MIPS_COBALT is not set @@ -115,10 +117,10 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5 # CONFIG_MIPS_MACHINE is not set # CONFIG_MIPS_MALTA is not set # CONFIG_MIPS_MIRAGE is not set +CONFIG_MIPS_MTX1=y CONFIG_MIPS_MT_DISABLED=y # CONFIG_MIPS_MT_SMP is not set # CONFIG_MIPS_MT_SMTC is not set -CONFIG_MIPS_MTX1=y # CONFIG_MIPS_PB1000 is not set # CONFIG_MIPS_PB1100 is not set # CONFIG_MIPS_PB1200 is not set @@ -126,7 +128,6 @@ CONFIG_MIPS_MTX1=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_SIM is not set # CONFIG_MIPS_XXS1500 is not set -CONFIG_MIPS=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_MTD_ALCHEMY is not set # CONFIG_MTD_CFI_INTELEXT is not set diff --git a/target/linux/avr32/config-default b/target/linux/avr32/config-default index ec6565f85..8842a3f02 100644 --- a/target/linux/avr32/config-default +++ b/target/linux/avr32/config-default @@ -78,6 +78,7 @@ CONFIG_NO_HZ=y CONFIG_NR_QUICK=2 # CONFIG_OWNERSHIP_TRACE is not set CONFIG_PAGEFLAGS_EXTENDED=y +# CONFIG_PATA_AT32 is not set CONFIG_PERFORMANCE_COUNTERS=y CONFIG_PHYLIB=y CONFIG_PHYS_OFFSET=0x10000000 diff --git a/target/linux/brcm-2.4/patches/004-flash.patch b/target/linux/brcm-2.4/patches/004-flash.patch index 7de8a82eb..cbcf0da3b 100644 --- a/target/linux/brcm-2.4/patches/004-flash.patch +++ b/target/linux/brcm-2.4/patches/004-flash.patch @@ -1,8 +1,8 @@ ---- a/arch/mips/bcm947xx/Makefile -+++ b/arch/mips/bcm947xx/Makefile -@@ -11,6 +11,7 @@ +--- a/arch/mips/bcm947xx/Makefile ++++ b/arch/mips/bcm947xx/Makefile +@@ -11,6 +11,7 @@ export-objs := export.o obj-y := prom.o setup.o time.o sbmips.o gpio.o - obj-y += nvram.o nvram_linux.o cfe_env.o hndpmu.o + obj-y += nvram.o cfe_env.o hndpmu.o obj-y += sbutils.o utils.o bcmsrom.o hndchipc.o +obj-y += sflash.o obj-$(CONFIG_PCI) += sbpci.o pcibios.o diff --git a/target/linux/brcm47xx/patches-2.6.30/220-bcm5354.patch b/target/linux/brcm47xx/patches-2.6.30/220-bcm5354.patch index 6aedfb2e5..65416086f 100644 --- a/target/linux/brcm47xx/patches-2.6.30/220-bcm5354.patch +++ b/target/linux/brcm47xx/patches-2.6.30/220-bcm5354.patch @@ -31,7 +31,7 @@ } --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c -@@ -1010,6 +1010,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus) +@@ -1012,6 +1012,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus) if (bus->chip_id == 0x5365) { rate = 100000000; diff --git a/target/linux/brcm47xx/patches-2.6.30/700-ssb-gigabit-ethernet-driver.patch b/target/linux/brcm47xx/patches-2.6.30/700-ssb-gigabit-ethernet-driver.patch index a524dff5d..f56ae8e71 100644 --- a/target/linux/brcm47xx/patches-2.6.30/700-ssb-gigabit-ethernet-driver.patch +++ b/target/linux/brcm47xx/patches-2.6.30/700-ssb-gigabit-ethernet-driver.patch @@ -98,7 +98,7 @@ /* Workaround for unstable PLL clock */ - if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) || - (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) { -+ if ((tp->phy_id & PHY_ID_MASK != PHY_ID_BCM5750_2) && ++ if ((tp->phy_id & PHY_ID_MASK) != PHY_ID_BCM5750_2 && + /* !!! FIXME !!! */ + ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) || + (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX))) { @@ -252,14 +252,6 @@ if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & ~GRC_LCLCTRL_GPIO_OUTPUT1); -@@ -12063,7 +12133,6 @@ static int __devinit tg3_get_invariants( - tp->write32 = tg3_write_flush_reg32; - } - -- - if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) || - (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) { - tp->write32_tx_mbox = tg3_write32_tx_mbox; @@ -12099,6 +12168,11 @@ static int __devinit tg3_get_invariants( GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701))) tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; diff --git a/target/linux/brcm47xx/patches-2.6.30/800-fix_cfe_detection.patch b/target/linux/brcm47xx/patches-2.6.30/800-fix_cfe_detection.patch index 6cba54053..c3a8a5738 100644 --- a/target/linux/brcm47xx/patches-2.6.30/800-fix_cfe_detection.patch +++ b/target/linux/brcm47xx/patches-2.6.30/800-fix_cfe_detection.patch @@ -90,7 +90,7 @@ { char buf[CL_SIZE]; -@@ -146,9 +122,12 @@ static __init void prom_init_mem(void) +@@ -154,9 +130,12 @@ static __init void prom_init_mem(void) void __init prom_init(void) { diff --git a/target/linux/brcm47xx/patches-2.6.31/100-board_support.patch b/target/linux/brcm47xx/patches-2.6.31/100-board_support.patch index b7291e66b..6fa0937d4 100644 --- a/target/linux/brcm47xx/patches-2.6.31/100-board_support.patch +++ b/target/linux/brcm47xx/patches-2.6.31/100-board_support.patch @@ -15,7 +15,7 @@ extern char *system_type; --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h -@@ -2085,6 +2085,7 @@ +@@ -2089,6 +2089,7 @@ #define PCI_DEVICE_ID_TIGON3_5906M 0x1713 #define PCI_DEVICE_ID_BCM4401 0x4401 #define PCI_DEVICE_ID_BCM4401B0 0x4402 diff --git a/target/linux/brcm47xx/patches-2.6.31/210-b44_phy_fix.patch b/target/linux/brcm47xx/patches-2.6.31/210-b44_phy_fix.patch index a9f4f9562..6bf52f7bc 100644 --- a/target/linux/brcm47xx/patches-2.6.31/210-b44_phy_fix.patch +++ b/target/linux/brcm47xx/patches-2.6.31/210-b44_phy_fix.patch @@ -9,7 +9,7 @@ } static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags) -@@ -2221,6 +2221,10 @@ static int __devinit b44_init_one(struct +@@ -2217,6 +2217,10 @@ static int __devinit b44_init_one(struct */ b44_chip_reset(bp, B44_CHIP_RESET_FULL); diff --git a/target/linux/brcm47xx/patches-2.6.31/220-bcm5354.patch b/target/linux/brcm47xx/patches-2.6.31/220-bcm5354.patch index 9adf48414..0d46f82c4 100644 --- a/target/linux/brcm47xx/patches-2.6.31/220-bcm5354.patch +++ b/target/linux/brcm47xx/patches-2.6.31/220-bcm5354.patch @@ -31,7 +31,7 @@ } --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c -@@ -1010,6 +1010,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus) +@@ -1012,6 +1012,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus) if (bus->chip_id == 0x5365) { rate = 100000000; diff --git a/target/linux/brcm47xx/patches-2.6.31/270-ehci-ssb.patch b/target/linux/brcm47xx/patches-2.6.31/270-ehci-ssb.patch index 5b205e0e7..8dc3ccd02 100644 --- a/target/linux/brcm47xx/patches-2.6.31/270-ehci-ssb.patch +++ b/target/linux/brcm47xx/patches-2.6.31/270-ehci-ssb.patch @@ -29,7 +29,7 @@ depends on USB --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c -@@ -1117,8 +1117,16 @@ MODULE_LICENSE ("GPL"); +@@ -1119,8 +1119,16 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ixp4xx_ehci_driver #endif diff --git a/target/linux/brcm47xx/patches-2.6.31/700-ssb-gigabit-ethernet-driver.patch b/target/linux/brcm47xx/patches-2.6.31/700-ssb-gigabit-ethernet-driver.patch index 4a47e63a7..027334388 100644 --- a/target/linux/brcm47xx/patches-2.6.31/700-ssb-gigabit-ethernet-driver.patch +++ b/target/linux/brcm47xx/patches-2.6.31/700-ssb-gigabit-ethernet-driver.patch @@ -98,7 +98,7 @@ /* Workaround for unstable PLL clock */ - if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) || - (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) { -+ if ((tp->phy_id & PHY_ID_MASK != PHY_ID_BCM5750_2) && ++ if ((tp->phy_id & PHY_ID_MASK) != PHY_ID_BCM5750_2 && + /* !!! FIXME !!! */ + ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) || + (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX))) { @@ -252,14 +252,6 @@ if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & ~GRC_LCLCTRL_GPIO_OUTPUT1); -@@ -12100,7 +12170,6 @@ static int __devinit tg3_get_invariants( - tp->write32 = tg3_write_flush_reg32; - } - -- - if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) || - (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) { - tp->write32_tx_mbox = tg3_write32_tx_mbox; @@ -12136,6 +12205,11 @@ static int __devinit tg3_get_invariants( GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701))) tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; diff --git a/target/linux/brcm47xx/patches-2.6.31/800-fix_cfe_detection.patch b/target/linux/brcm47xx/patches-2.6.31/800-fix_cfe_detection.patch index 6cba54053..c3a8a5738 100644 --- a/target/linux/brcm47xx/patches-2.6.31/800-fix_cfe_detection.patch +++ b/target/linux/brcm47xx/patches-2.6.31/800-fix_cfe_detection.patch @@ -90,7 +90,7 @@ { char buf[CL_SIZE]; -@@ -146,9 +122,12 @@ static __init void prom_init_mem(void) +@@ -154,9 +130,12 @@ static __init void prom_init_mem(void) void __init prom_init(void) { diff --git a/target/linux/brcm47xx/patches-2.6.32/100-board_support.patch b/target/linux/brcm47xx/patches-2.6.32/100-board_support.patch index ce5160eb9..b1aea5f31 100644 --- a/target/linux/brcm47xx/patches-2.6.32/100-board_support.patch +++ b/target/linux/brcm47xx/patches-2.6.32/100-board_support.patch @@ -1,8 +1,8 @@ --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h -@@ -57,6 +57,12 @@ - #define MACH_MIKROTIK_RB532 0 /* Mikrotik RouterBoard 532 */ - #define MACH_MIKROTIK_RB532A 1 /* Mikrotik RouterBoard 532A */ +@@ -69,6 +69,12 @@ + #define MACH_DEXXON_GDIUM2F10 5 + #define MACH_LOONGSON_END 6 +/* + * Valid machtype for group Broadcom @@ -15,7 +15,7 @@ extern char *system_type; --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h -@@ -2106,6 +2106,7 @@ +@@ -2101,6 +2101,7 @@ #define PCI_DEVICE_ID_TIGON3_5906M 0x1713 #define PCI_DEVICE_ID_BCM4401 0x4401 #define PCI_DEVICE_ID_BCM4401B0 0x4402 diff --git a/target/linux/brcm47xx/patches-2.6.32/110-flash_map.patch b/target/linux/brcm47xx/patches-2.6.32/110-flash_map.patch index 59e89e575..a2c3fab79 100644 --- a/target/linux/brcm47xx/patches-2.6.32/110-flash_map.patch +++ b/target/linux/brcm47xx/patches-2.6.32/110-flash_map.patch @@ -1,6 +1,6 @@ --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig -@@ -343,6 +343,12 @@ config MTD_CFI_FLAGADM +@@ -327,6 +327,12 @@ config MTD_CFI_FLAGADM Mapping for the Flaga digital module. If you don't have one, ignore this setting. @@ -15,7 +15,7 @@ depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile -@@ -29,6 +29,7 @@ obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcm +@@ -28,6 +28,7 @@ obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcms obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o diff --git a/target/linux/brcm47xx/patches-2.6.32/130-remove_scache.patch b/target/linux/brcm47xx/patches-2.6.32/130-remove_scache.patch index 4ed30486d..b649ec344 100644 --- a/target/linux/brcm47xx/patches-2.6.32/130-remove_scache.patch +++ b/target/linux/brcm47xx/patches-2.6.32/130-remove_scache.patch @@ -1,6 +1,6 @@ --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -195,7 +195,6 @@ config MIPS_MALTA +@@ -216,7 +216,6 @@ config MIPS_MALTA select I8259 select MIPS_BOARDS_GEN select MIPS_BONITO64 @@ -8,7 +8,7 @@ select PCI_GT64XXX_PCI0 select MIPS_MSC select SWAP_IO_SPACE -@@ -1473,13 +1472,6 @@ config IP22_CPU_SCACHE +@@ -1523,13 +1522,6 @@ config IP22_CPU_SCACHE bool select BOARD_SCACHE @@ -24,7 +24,7 @@ select BOARD_SCACHE --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c -@@ -753,6 +753,8 @@ static inline void cpu_probe_mips(struct +@@ -748,6 +748,8 @@ static inline void cpu_probe_mips(struct case PRID_IMP_25KF: c->cputype = CPU_25KF; __cpu_name[cpu] = "MIPS 25Kc"; @@ -35,7 +35,7 @@ c->cputype = CPU_34K; --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile -@@ -32,6 +32,5 @@ obj-$(CONFIG_CPU_CAVIUM_OCTEON) += c-oct +@@ -33,6 +33,5 @@ obj-$(CONFIG_CPU_CAVIUM_OCTEON) += c-oct obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o @@ -44,7 +44,7 @@ EXTRA_CFLAGS += -Werror --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c -@@ -1135,7 +1135,6 @@ static void __init loongson2_sc_init(voi +@@ -1148,7 +1148,6 @@ static void __init loongson2_sc_init(voi extern int r5k_sc_init(void); extern int rm7k_sc_init(void); @@ -52,7 +52,7 @@ static void __cpuinit setup_scache(void) { -@@ -1189,29 +1188,17 @@ static void __cpuinit setup_scache(void) +@@ -1202,29 +1201,17 @@ static void __cpuinit setup_scache(void) #endif default: diff --git a/target/linux/brcm47xx/patches-2.6.32/150-cpu_fixes.patch b/target/linux/brcm47xx/patches-2.6.32/150-cpu_fixes.patch index f5209d4fe..9e3309307 100644 --- a/target/linux/brcm47xx/patches-2.6.32/150-cpu_fixes.patch +++ b/target/linux/brcm47xx/patches-2.6.32/150-cpu_fixes.patch @@ -345,7 +345,7 @@ } --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c -@@ -784,6 +784,9 @@ static void __cpuinit build_r4000_tlb_re +@@ -739,6 +739,9 @@ static void __cpuinit build_r4000_tlb_re /* No need for uasm_i_nop */ } @@ -355,7 +355,7 @@ #ifdef CONFIG_64BIT build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */ #else -@@ -1238,6 +1241,9 @@ build_r4000_tlbchange_handler_head(u32 * +@@ -1193,6 +1196,9 @@ build_r4000_tlbchange_handler_head(u32 * struct uasm_reloc **r, unsigned int pte, unsigned int ptr) { diff --git a/target/linux/brcm47xx/patches-2.6.32/160-kmap_coherent.patch b/target/linux/brcm47xx/patches-2.6.32/160-kmap_coherent.patch index ef1cacdba..9cba353da 100644 --- a/target/linux/brcm47xx/patches-2.6.32/160-kmap_coherent.patch +++ b/target/linux/brcm47xx/patches-2.6.32/160-kmap_coherent.patch @@ -1,6 +1,6 @@ --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h -@@ -104,6 +104,9 @@ +@@ -107,6 +107,9 @@ #ifndef cpu_has_pindexed_dcache #define cpu_has_pindexed_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX) #endif @@ -28,7 +28,7 @@ +#endif /* __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H */ --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c -@@ -494,7 +494,7 @@ static inline void local_r4k_flush_cache +@@ -507,7 +507,7 @@ static inline void local_r4k_flush_cache */ map_coherent = (cpu_has_dc_aliases && page_mapped(page) && !Page_dcache_dirty(page)); @@ -37,7 +37,7 @@ vaddr = kmap_coherent(page, addr); else vaddr = kmap_atomic(page, KM_USER0); -@@ -517,7 +517,7 @@ static inline void local_r4k_flush_cache +@@ -530,7 +530,7 @@ static inline void local_r4k_flush_cache } if (vaddr) { @@ -48,7 +48,7 @@ kunmap_atomic(vaddr, KM_USER0); --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c -@@ -204,7 +204,7 @@ void copy_user_highpage(struct page *to, +@@ -209,7 +209,7 @@ void copy_user_highpage(struct page *to, void *vfrom, *vto; vto = kmap_atomic(to, KM_USER1); @@ -57,7 +57,7 @@ page_mapped(from) && !Page_dcache_dirty(from)) { vfrom = kmap_coherent(from, vaddr); copy_page(vto, vfrom); -@@ -226,7 +226,7 @@ void copy_to_user_page(struct vm_area_st +@@ -231,7 +231,7 @@ void copy_to_user_page(struct vm_area_st struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) { @@ -66,7 +66,7 @@ page_mapped(page) && !Page_dcache_dirty(page)) { void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(vto, src, len); -@@ -244,7 +244,7 @@ void copy_from_user_page(struct vm_area_ +@@ -249,7 +249,7 @@ void copy_from_user_page(struct vm_area_ struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) { diff --git a/target/linux/brcm47xx/patches-2.6.32/210-b44_phy_fix.patch b/target/linux/brcm47xx/patches-2.6.32/210-b44_phy_fix.patch index 51b65afa6..3540c23e7 100644 --- a/target/linux/brcm47xx/patches-2.6.32/210-b44_phy_fix.patch +++ b/target/linux/brcm47xx/patches-2.6.32/210-b44_phy_fix.patch @@ -9,7 +9,7 @@ } static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags) -@@ -2220,6 +2220,10 @@ static int __devinit b44_init_one(struct +@@ -2223,6 +2223,10 @@ static int __devinit b44_init_one(struct */ b44_chip_reset(bp, B44_CHIP_RESET_FULL); diff --git a/target/linux/brcm47xx/patches-2.6.32/220-bcm5354.patch b/target/linux/brcm47xx/patches-2.6.32/220-bcm5354.patch index 6aedfb2e5..360751a7a 100644 --- a/target/linux/brcm47xx/patches-2.6.32/220-bcm5354.patch +++ b/target/linux/brcm47xx/patches-2.6.32/220-bcm5354.patch @@ -20,7 +20,7 @@ switch (*plltype) { --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c -@@ -161,6 +161,8 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m +@@ -217,6 +217,8 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) { rate = 200000000; @@ -31,7 +31,7 @@ } --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c -@@ -1010,6 +1010,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus) +@@ -1066,6 +1066,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus) if (bus->chip_id == 0x5365) { rate = 100000000; diff --git a/target/linux/brcm47xx/patches-2.6.32/260-ohci-set-dma-mask.patch b/target/linux/brcm47xx/patches-2.6.32/260-ohci-set-dma-mask.patch index 50dcd5718..962779847 100644 --- a/target/linux/brcm47xx/patches-2.6.32/260-ohci-set-dma-mask.patch +++ b/target/linux/brcm47xx/patches-2.6.32/260-ohci-set-dma-mask.patch @@ -8,7 +8,7 @@ int err = -ENOMEM; u32 tmp, flags = 0; -+ if (ssb_dma_set_mask(dev, DMA_32BIT_MASK)) ++ if (ssb_dma_set_mask(dev, DMA_BIT_MASK(32))) + return -EOPNOTSUPP; + if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) { diff --git a/target/linux/brcm47xx/patches-2.6.32/270-ehci-ssb.patch b/target/linux/brcm47xx/patches-2.6.32/270-ehci-ssb.patch index d1421332b..8316b9840 100644 --- a/target/linux/brcm47xx/patches-2.6.32/270-ehci-ssb.patch +++ b/target/linux/brcm47xx/patches-2.6.32/270-ehci-ssb.patch @@ -7,7 +7,7 @@ --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig -@@ -106,6 +106,19 @@ config USB_OXU210HP_HCD +@@ -132,6 +132,19 @@ config USB_OXU210HP_HCD To compile this driver as a module, choose M here: the module will be called oxu210hp-hcd. @@ -29,8 +29,8 @@ depends on USB --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c -@@ -1075,8 +1075,16 @@ MODULE_LICENSE ("GPL"); - #define PLATFORM_DRIVER ixp4xx_ehci_driver +@@ -1141,8 +1141,16 @@ MODULE_LICENSE ("GPL"); + #define PLATFORM_DRIVER ehci_atmel_driver #endif -#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ diff --git a/target/linux/brcm47xx/patches-2.6.32/280-activate_ssb_support_in_usb.patch b/target/linux/brcm47xx/patches-2.6.32/280-activate_ssb_support_in_usb.patch index aeb9d334c..f22415856 100644 --- a/target/linux/brcm47xx/patches-2.6.32/280-activate_ssb_support_in_usb.patch +++ b/target/linux/brcm47xx/patches-2.6.32/280-activate_ssb_support_in_usb.patch @@ -5,7 +5,7 @@ This prevents the options from being delete with make kernel_oldconfig. --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig -@@ -126,6 +126,8 @@ config SSB_DRIVER_MIPS +@@ -140,6 +140,8 @@ config SSB_DRIVER_MIPS config SSB_EMBEDDED bool depends on SSB_DRIVER_MIPS diff --git a/target/linux/brcm47xx/patches-2.6.32/301-kmod-fuse-dcache-bug-r4k.patch b/target/linux/brcm47xx/patches-2.6.32/301-kmod-fuse-dcache-bug-r4k.patch index 6e1b130e9..e960dbacc 100644 --- a/target/linux/brcm47xx/patches-2.6.32/301-kmod-fuse-dcache-bug-r4k.patch +++ b/target/linux/brcm47xx/patches-2.6.32/301-kmod-fuse-dcache-bug-r4k.patch @@ -1,6 +1,6 @@ --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c -@@ -360,7 +360,7 @@ static inline void local_r4k___flush_cac +@@ -373,7 +373,7 @@ static inline void local_r4k___flush_cac } } @@ -9,7 +9,7 @@ { r4k_on_each_cpu(local_r4k___flush_cache_all, NULL, 1); } -@@ -524,7 +524,7 @@ static inline void local_r4k_flush_cache +@@ -537,7 +537,7 @@ static inline void local_r4k_flush_cache } } @@ -18,7 +18,7 @@ unsigned long addr, unsigned long pfn) { struct flush_cache_page_args args; -@@ -1443,3 +1443,10 @@ void __cpuinit r4k_cache_init(void) +@@ -1456,3 +1456,10 @@ void __cpuinit r4k_cache_init(void) coherency_setup(); #endif } diff --git a/target/linux/brcm47xx/patches-2.6.32/302-kmod-fuse-dcache-bug-fuse.patch b/target/linux/brcm47xx/patches-2.6.32/302-kmod-fuse-dcache-bug-fuse.patch index 79515d444..d6c0b3ab5 100644 --- a/target/linux/brcm47xx/patches-2.6.32/302-kmod-fuse-dcache-bug-fuse.patch +++ b/target/linux/brcm47xx/patches-2.6.32/302-kmod-fuse-dcache-bug-fuse.patch @@ -1,6 +1,6 @@ --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c -@@ -527,6 +527,11 @@ static void fuse_copy_finish(struct fuse +@@ -533,6 +533,11 @@ static void fuse_copy_finish(struct fuse } } @@ -12,7 +12,7 @@ /* * Get another pagefull of userspace buffer, and map it to kernel * address space, and lock request -@@ -535,6 +540,9 @@ static int fuse_copy_fill(struct fuse_co +@@ -541,6 +546,9 @@ static int fuse_copy_fill(struct fuse_co { unsigned long offset; int err; @@ -22,7 +22,7 @@ unlock_request(cs->fc, cs->req); fuse_copy_finish(cs); -@@ -546,14 +554,22 @@ static int fuse_copy_fill(struct fuse_co +@@ -552,14 +560,22 @@ static int fuse_copy_fill(struct fuse_co cs->nr_segs--; } down_read(¤t->mm->mmap_sem); @@ -45,7 +45,7 @@ cs->buf = cs->mapaddr + offset; cs->len = min(PAGE_SIZE - offset, cs->seglen); cs->seglen -= cs->len; -@@ -567,6 +583,11 @@ static int fuse_copy_do(struct fuse_copy +@@ -573,6 +589,11 @@ static int fuse_copy_do(struct fuse_copy { unsigned ncpy = min(*size, cs->len); if (val) { @@ -69,7 +69,7 @@ #include --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c -@@ -1055,6 +1055,10 @@ static int __init fuse_init(void) +@@ -1201,6 +1201,10 @@ static int __init fuse_init(void) printk(KERN_INFO "fuse init (API version %i.%i)\n", FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); diff --git a/target/linux/brcm47xx/patches-2.6.32/310-no_highpage.patch b/target/linux/brcm47xx/patches-2.6.32/310-no_highpage.patch index 45ce36a11..cde3cbf72 100644 --- a/target/linux/brcm47xx/patches-2.6.32/310-no_highpage.patch +++ b/target/linux/brcm47xx/patches-2.6.32/310-no_highpage.patch @@ -1,6 +1,6 @@ --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h -@@ -35,6 +35,7 @@ +@@ -43,6 +43,7 @@ #ifndef __ASSEMBLY__ #include @@ -8,7 +8,7 @@ #include extern void build_clear_page(void); -@@ -70,13 +71,16 @@ static inline void clear_user_page(void +@@ -78,13 +79,16 @@ static inline void clear_user_page(void flush_data_cache_page((unsigned long)addr); } @@ -33,7 +33,7 @@ * These are used to make use of C type-checking.. --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c -@@ -198,30 +198,6 @@ void kunmap_coherent(void) +@@ -203,30 +203,6 @@ void kunmap_coherent(void) preempt_check_resched(); } diff --git a/target/linux/brcm47xx/patches-2.6.32/400-arch-bcm47xx.patch b/target/linux/brcm47xx/patches-2.6.32/400-arch-bcm47xx.patch index ef6b71267..e2886f464 100644 --- a/target/linux/brcm47xx/patches-2.6.32/400-arch-bcm47xx.patch +++ b/target/linux/brcm47xx/patches-2.6.32/400-arch-bcm47xx.patch @@ -1,6 +1,6 @@ --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -53,6 +53,7 @@ config BCM47XX +@@ -74,6 +74,7 @@ config BCM47XX select SSB_DRIVER_MIPS select SSB_DRIVER_EXTIF select SSB_EMBEDDED diff --git a/target/linux/brcm47xx/patches-2.6.32/700-ssb-gigabit-ethernet-driver.patch b/target/linux/brcm47xx/patches-2.6.32/700-ssb-gigabit-ethernet-driver.patch index 8cf9f8e38..de2501950 100644 --- a/target/linux/brcm47xx/patches-2.6.32/700-ssb-gigabit-ethernet-driver.patch +++ b/target/linux/brcm47xx/patches-2.6.32/700-ssb-gigabit-ethernet-driver.patch @@ -8,7 +8,7 @@ #include #include -@@ -446,8 +447,9 @@ static void _tw32_flush(struct tg3 *tp, +@@ -457,8 +458,9 @@ static void _tw32_flush(struct tg3 *tp, static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val) { tp->write32_mbox(tp, off, val); @@ -20,7 +20,7 @@ tp->read32_mbox(tp, off); } -@@ -457,7 +459,7 @@ static void tg3_write32_tx_mbox(struct t +@@ -468,7 +470,7 @@ static void tg3_write32_tx_mbox(struct t writel(val, mbox); if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) writel(val, mbox); @@ -29,7 +29,7 @@ readl(mbox); } -@@ -729,7 +731,7 @@ static void tg3_switch_clocks(struct tg3 +@@ -768,7 +770,7 @@ static void tg3_switch_clocks(struct tg3 #define PHY_BUSY_LOOPS 5000 @@ -38,7 +38,7 @@ { u32 frame_val; unsigned int loops; -@@ -778,7 +780,12 @@ static int tg3_readphy(struct tg3 *tp, i +@@ -817,7 +819,12 @@ static int tg3_readphy(struct tg3 *tp, i return ret; } @@ -52,7 +52,7 @@ { u32 frame_val; unsigned int loops; -@@ -827,6 +834,11 @@ static int tg3_writephy(struct tg3 *tp, +@@ -866,6 +873,11 @@ static int tg3_writephy(struct tg3 *tp, return ret; } @@ -64,7 +64,7 @@ static int tg3_bmcr_reset(struct tg3 *tp) { u32 phy_control; -@@ -2263,6 +2275,9 @@ static int tg3_nvram_read(struct tg3 *tp +@@ -2337,6 +2349,9 @@ static int tg3_nvram_read(struct tg3 *tp { int ret; @@ -74,20 +74,20 @@ if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) return tg3_nvram_read_using_eeprom(tp, offset, val); -@@ -2594,8 +2609,10 @@ static int tg3_set_power_state(struct tg +@@ -2668,8 +2683,10 @@ static int tg3_set_power_state(struct tg tg3_frob_aux_power(tp); /* Workaround for unstable PLL clock */ - if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) || - (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) { -+ if ((tp->phy_id & PHY_ID_MASK != PHY_ID_BCM5750_2) && ++ if ((tp->phy_id & PHY_ID_MASK) != PHY_ID_BCM5750_2 && + /* !!! FIXME !!! */ + ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) || + (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX))) { u32 val = tr32(0x7d00); val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1); -@@ -3087,6 +3104,14 @@ relink: +@@ -3161,6 +3178,14 @@ relink: tg3_phy_copper_begin(tp); @@ -102,7 +102,7 @@ tg3_readphy(tp, MII_BMSR, &tmp); if (!tg3_readphy(tp, MII_BMSR, &tmp) && (tmp & BMSR_LSTATUS)) -@@ -6000,6 +6025,11 @@ static int tg3_poll_fw(struct tg3 *tp) +@@ -6264,6 +6289,11 @@ static int tg3_poll_fw(struct tg3 *tp) int i; u32 val; @@ -114,7 +114,7 @@ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { /* Wait up to 20ms for init done. */ for (i = 0; i < 200; i++) { -@@ -6257,6 +6287,14 @@ static int tg3_chip_reset(struct tg3 *tp +@@ -6541,6 +6571,14 @@ static int tg3_chip_reset(struct tg3 *tp tw32(0x5000, 0x400); } @@ -129,7 +129,7 @@ tw32(GRC_MODE, tp->grc_mode); if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) { -@@ -6409,9 +6447,12 @@ static int tg3_halt_cpu(struct tg3 *tp, +@@ -6695,9 +6733,12 @@ static int tg3_halt_cpu(struct tg3 *tp, return -ENODEV; } @@ -145,7 +145,7 @@ return 0; } -@@ -6474,6 +6515,11 @@ static int tg3_load_5701_a0_firmware_fix +@@ -6760,6 +6801,11 @@ static int tg3_load_5701_a0_firmware_fix const __be32 *fw_data; int err, i; @@ -157,7 +157,7 @@ fw_data = (void *)tp->fw->data; /* Firmware blob starts with version numbers, followed by -@@ -6533,6 +6579,11 @@ static int tg3_load_tso_firmware(struct +@@ -6819,6 +6865,11 @@ static int tg3_load_tso_firmware(struct unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size; int err, i; @@ -169,7 +169,7 @@ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) return 0; -@@ -7444,6 +7495,11 @@ static void tg3_timer(unsigned long __op +@@ -7906,6 +7957,11 @@ static void tg3_timer(unsigned long __op spin_lock(&tp->lock); @@ -181,7 +181,7 @@ if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { /* All of this garbage is because when using non-tagged * IRQ status the mailbox/status_block protocol the chip -@@ -9217,6 +9273,11 @@ static int tg3_test_nvram(struct tg3 *tp +@@ -9791,6 +9847,11 @@ static int tg3_test_nvram(struct tg3 *tp if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) return 0; @@ -193,7 +193,7 @@ if (tg3_nvram_read(tp, 0, &magic) != 0) return -EIO; -@@ -10010,7 +10071,7 @@ static int tg3_ioctl(struct net_device * +@@ -10585,7 +10646,7 @@ static int tg3_ioctl(struct net_device * return -EAGAIN; spin_lock_bh(&tp->lock); @@ -202,7 +202,7 @@ spin_unlock_bh(&tp->lock); data->val_out = mii_regval; -@@ -10029,7 +10090,7 @@ static int tg3_ioctl(struct net_device * +@@ -10601,7 +10662,7 @@ static int tg3_ioctl(struct net_device * return -EAGAIN; spin_lock_bh(&tp->lock); @@ -211,7 +211,7 @@ spin_unlock_bh(&tp->lock); return err; -@@ -10619,6 +10680,12 @@ static void __devinit tg3_get_57780_nvra +@@ -11246,6 +11307,12 @@ static void __devinit tg3_get_5717_nvram /* Chips other than 5700/5701 use the NVRAM for fetching info. */ static void __devinit tg3_nvram_init(struct tg3 *tp) { @@ -224,7 +224,7 @@ tw32_f(GRC_EEPROM_ADDR, (EEPROM_ADDR_FSM_RESET | (EEPROM_DEFAULT_CLOCK_PERIOD << -@@ -10877,6 +10944,9 @@ static int tg3_nvram_write_block(struct +@@ -11506,6 +11573,9 @@ static int tg3_nvram_write_block(struct { int ret; @@ -234,7 +234,7 @@ if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & ~GRC_LCLCTRL_GPIO_OUTPUT1); -@@ -12136,6 +12205,11 @@ static int __devinit tg3_get_invariants( +@@ -12788,6 +12858,11 @@ static int __devinit tg3_get_invariants( GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701))) tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; @@ -246,7 +246,7 @@ /* Get eeprom hw config before calling tg3_set_power_state(). * In particular, the TG3_FLG2_IS_NIC flag must be * determined before calling tg3_set_power_state() so that -@@ -12513,6 +12587,10 @@ static int __devinit tg3_get_device_addr +@@ -13177,6 +13252,10 @@ static int __devinit tg3_get_device_addr } if (!is_valid_ether_addr(&dev->dev_addr[0])) { @@ -257,7 +257,7 @@ #ifdef CONFIG_SPARC if (!tg3_get_default_macaddr_sparc(tp)) return 0; -@@ -13004,6 +13082,7 @@ static char * __devinit tg3_phy_string(s +@@ -13669,6 +13748,7 @@ static char * __devinit tg3_phy_string(s case PHY_ID_BCM5704: return "5704"; case PHY_ID_BCM5705: return "5705"; case PHY_ID_BCM5750: return "5750"; @@ -265,7 +265,7 @@ case PHY_ID_BCM5752: return "5752"; case PHY_ID_BCM5714: return "5714"; case PHY_ID_BCM5780: return "5780"; -@@ -13214,6 +13293,13 @@ static int __devinit tg3_init_one(struct +@@ -13880,6 +13960,13 @@ static int __devinit tg3_init_one(struct tp->msg_enable = tg3_debug; else tp->msg_enable = TG3_DEF_MSG_ENABLE; @@ -281,7 +281,7 @@ * swapping. DMA data byte swapping is controlled in the GRC_MODE --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h -@@ -1853,6 +1853,9 @@ +@@ -1939,6 +1939,9 @@ #define NIC_SRAM_RGMII_STD_IBND_DISABLE 0x00000004 #define NIC_SRAM_RGMII_EXT_IBND_RX_EN 0x00000008 #define NIC_SRAM_RGMII_EXT_IBND_TX_EN 0x00000010 @@ -291,7 +291,7 @@ #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 -@@ -2701,6 +2704,7 @@ struct tg3 { +@@ -2821,6 +2824,7 @@ struct tg3 { #define PHY_ID_BCM5714 0x60008340 #define PHY_ID_BCM5780 0x60008350 #define PHY_ID_BCM5755 0xbc050cc0 @@ -299,7 +299,7 @@ #define PHY_ID_BCM5787 0xbc050ce0 #define PHY_ID_BCM5756 0xbc050ed0 #define PHY_ID_BCM5784 0xbc050fa0 -@@ -2745,7 +2749,7 @@ struct tg3 { +@@ -2865,7 +2869,7 @@ struct tg3 { (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \ (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \ diff --git a/target/linux/brcm47xx/patches-2.6.32/800-fix_cfe_detection.patch b/target/linux/brcm47xx/patches-2.6.32/800-fix_cfe_detection.patch index 6cba54053..a8a14105e 100644 --- a/target/linux/brcm47xx/patches-2.6.32/800-fix_cfe_detection.patch +++ b/target/linux/brcm47xx/patches-2.6.32/800-fix_cfe_detection.patch @@ -88,9 +88,9 @@ -static __init void prom_init_cmdline(void) +static __init void prom_init_cmdline_cfe(void) { - char buf[CL_SIZE]; + static char buf[CL_SIZE] __initdata; -@@ -146,9 +122,12 @@ static __init void prom_init_mem(void) +@@ -154,9 +130,12 @@ static __init void prom_init_mem(void) void __init prom_init(void) { diff --git a/target/linux/brcm47xx/patches-2.6.32/900-disable_early_printk.patch b/target/linux/brcm47xx/patches-2.6.32/900-disable_early_printk.patch index 3f1aeef8d..8d65f7848 100644 --- a/target/linux/brcm47xx/patches-2.6.32/900-disable_early_printk.patch +++ b/target/linux/brcm47xx/patches-2.6.32/900-disable_early_printk.patch @@ -1,6 +1,6 @@ --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -56,7 +56,6 @@ config BCM47XX +@@ -77,7 +77,6 @@ config BCM47XX select SSB_B43_PCI_BRIDGE if PCI select SSB_PCICORE_HOSTMODE if PCI select GENERIC_GPIO diff --git a/target/linux/brcm47xx/patches-2.6.32/920-cache-wround.patch b/target/linux/brcm47xx/patches-2.6.32/920-cache-wround.patch index e9b37e7b5..3a527df25 100644 --- a/target/linux/brcm47xx/patches-2.6.32/920-cache-wround.patch +++ b/target/linux/brcm47xx/patches-2.6.32/920-cache-wround.patch @@ -31,7 +31,7 @@ --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c -@@ -544,6 +544,9 @@ build_get_pgde32(u32 **p, unsigned int t +@@ -601,6 +601,9 @@ build_get_pgde32(u32 **p, unsigned int t #endif uasm_i_addu(p, ptr, tmp, ptr); #else @@ -41,7 +41,7 @@ UASM_i_LA_mostly(p, ptr, pgdc); #endif uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */ -@@ -674,12 +677,12 @@ static void __cpuinit build_r4000_tlb_re +@@ -739,12 +742,12 @@ static void __cpuinit build_r4000_tlb_re /* No need for uasm_i_nop */ } @@ -57,7 +57,7 @@ build_get_pgde32(&p, K0, K1); /* get pgd in K1 */ #endif -@@ -687,6 +690,9 @@ static void __cpuinit build_r4000_tlb_re +@@ -756,6 +759,9 @@ static void __cpuinit build_r4000_tlb_re build_update_entries(&p, K0, K1); build_tlb_write_entry(&p, &l, &r, tlb_random); uasm_l_leave(&l, p); @@ -66,8 +66,8 @@ +#endif uasm_i_eret(&p); /* return from trap */ - #ifdef CONFIG_64BIT -@@ -1084,12 +1090,12 @@ build_r4000_tlbchange_handler_head(u32 * + #ifdef CONFIG_HUGETLB_PAGE +@@ -1196,12 +1202,12 @@ build_r4000_tlbchange_handler_head(u32 * struct uasm_reloc **r, unsigned int pte, unsigned int ptr) { @@ -83,7 +83,7 @@ build_get_pgde32(p, pte, ptr); /* get pgd in ptr */ #endif -@@ -1117,6 +1123,9 @@ build_r4000_tlbchange_handler_tail(u32 * +@@ -1238,6 +1244,9 @@ build_r4000_tlbchange_handler_tail(u32 * build_update_entries(p, tmp, ptr); build_tlb_write_entry(p, l, r, tlb_indexed); uasm_l_leave(l, *p); diff --git a/target/linux/brcm63xx/files-2.6.30/arch/mips/bcm63xx/boards/board_bcm963xx.c b/target/linux/brcm63xx/files-2.6.30/arch/mips/bcm63xx/boards/board_bcm963xx.c index 97374f897..280383a6a 100644 --- a/target/linux/brcm63xx/files-2.6.30/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/target/linux/brcm63xx/files-2.6.30/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -930,6 +930,7 @@ static struct platform_device bcm63xx_gpio_buttons_device = { int __init board_register_devices(void) { u32 val; + int led_count = 0; bcm63xx_uart_register(); bcm63xx_wdt_register(); @@ -986,7 +987,11 @@ int __init board_register_devices(void) /* Register GPIODEV */ platform_device_register_simple("GPIODEV", 0, &gpiodev_resource, 1); - bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds); + /* count number of LEDs defined by this device */ + while (led_count < ARRAY_SIZE(board.leds) && board.leds[led_count].name) + led_count++; + + bcm63xx_led_data.num_leds = led_count; bcm63xx_led_data.leds = board.leds; platform_device_register(&bcm63xx_gpio_leds); diff --git a/target/linux/brcm63xx/patches-2.6.30/070_bcm63xx_enet_vlan_incoming_fixed.patch b/target/linux/brcm63xx/patches-2.6.30/070_bcm63xx_enet_vlan_incoming_fixed.patch new file mode 100644 index 000000000..f18830ff2 --- /dev/null +++ b/target/linux/brcm63xx/patches-2.6.30/070_bcm63xx_enet_vlan_incoming_fixed.patch @@ -0,0 +1,13 @@ +Index: linux-2.6.30.10/drivers/net/bcm63xx_enet.c +=================================================================== +--- linux-2.6.30.10.orig/drivers/net/bcm63xx_enet.c 2010-02-18 12:57:05.332799586 -0500 ++++ linux-2.6.30.10/drivers/net/bcm63xx_enet.c 2010-02-18 12:57:53.954051082 -0500 +@@ -1520,7 +1520,7 @@ + actual_mtu = mtu; + + /* add ethernet header + vlan tag size */ +- actual_mtu += VLAN_ETH_HLEN; ++ actual_mtu += VLAN_ETH_HLEN + VLAN_HLEN; + + if (actual_mtu < 64 || actual_mtu > BCMENET_MAX_MTU) + return -EINVAL; diff --git a/target/linux/cobalt/config-2.6.32 b/target/linux/cobalt/config-2.6.32 new file mode 100644 index 000000000..e1ade55f0 --- /dev/null +++ b/target/linux/cobalt/config-2.6.32 @@ -0,0 +1,237 @@ +# CONFIG_32BIT is not set +# CONFIG_ALCHEMY_GPIO_INDIRECT is not set +# CONFIG_AR7 is not set +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_ARPD is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BRIDGE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set +# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_CPU_CAVIUM_OCTEON is not set +# CONFIG_CPU_LOONGSON2E is not set +# CONFIG_CPU_MIPS32_R1 is not set +# CONFIG_CPU_MIPS32_R2 is not set +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R5500 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_DE4X5 is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_DM9000 is not set +# CONFIG_DM9102 is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HIGH_RES_TIMERS is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_HZ_100 is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_MULTICAST is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LOGO is not set +# CONFIG_MACH_ALCHEMY is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_LOONGSON is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MII is not set +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MIPS_MACHINE is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_MT_SMP is not set +# CONFIG_MIPS_MT_SMTC is not set +# CONFIG_MIPS_SIM is not set +# CONFIG_MISC_DEVICES is not set +# CONFIG_MTD_BLOCK is not set +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_CFI_INTELEXT is not set +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NET_PCI is not set +# CONFIG_NO_IOPORT is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_PACKET_MMAP is not set +# CONFIG_PARTITION_ADVANCED is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SLAB is not set +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_ULI526X is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_WATCHDOG is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_WLAN_80211 is not set +CONFIG_64BIT=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SUPPORTS_OPROFILE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ATA=y +CONFIG_BINFMT_ELF32=y +CONFIG_BITREVERSE=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLOCK_COMPAT=y +CONFIG_CEVT_GT641XX=y +CONFIG_CEVT_R4K=y +CONFIG_CEVT_R4K_LIB=y +CONFIG_CFG80211_DEFAULT_PS_VALUE=0 +CONFIG_COMPAT=y +CONFIG_COMPAT_BRK=y +CONFIG_COMPAT_NETLINK_MESSAGES=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_CPU_NEVADA=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y +CONFIG_CRC16=y +CONFIG_CSRC_R4K=y +CONFIG_CSRC_R4K_LIB=y +CONFIG_DE2104X=y +CONFIG_DE2104X_DSL=0 +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DEVKMEM=y +CONFIG_DEVPORT=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_DNOTIFY=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_EARLY_PRINTK=y +CONFIG_ELF_CORE=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FB=y +CONFIG_FB_COBALT=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_FS_POSIX_ACL=y +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_SYSCALL_WRAPPERS=y +CONFIG_HID=m +CONFIG_HID_SUPPORT=y +CONFIG_HW_CONSOLE=y +CONFIG_HW_HAS_PCI=y +CONFIG_HZ=250 +CONFIG_HZ_250=y +CONFIG_I8253=y +CONFIG_I8259=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_INPUT=y +CONFIG_INPUT_COBALT_BTNS=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_POLLDEV=y +CONFIG_IRQ_CPU=y +CONFIG_IRQ_GT641XX=y +CONFIG_KEXEC=y +CONFIG_LEDS_COBALT_QUBE=y +CONFIG_LEDS_COBALT_RAQ=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_MIPS32_COMPAT=y +CONFIG_MIPS32_N32=y +CONFIG_MIPS32_O32=y +CONFIG_MIPS=y +CONFIG_MIPS_COBALT=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 +CONFIG_MIPS_MT_DISABLED=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_PHYSMAP=y +CONFIG_NET_TULIP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PATA_VIA=y +CONFIG_PCI_DISABLE_COMMON_QUIRKS=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_GT64XXX_PCI0=y +CONFIG_PCI_LEGACY=y +CONFIG_PCSPKR_PLATFORM=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_RAID_ATTRS=y +CONFIG_RELAY=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_SATA_PMP=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_SCSI=y +CONFIG_SECCOMP=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SLUB=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SYS_HAS_CPU_NEVADA=y +CONFIG_SYS_HAS_EARLY_PRINTK=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TREE_RCU=y +CONFIG_TULIP=y +CONFIG_TULIP_MMIO=y +CONFIG_TULIP_MWI=y +CONFIG_TULIP_NAPI=y +CONFIG_TULIP_NAPI_HW_MITIGATION=y +CONFIG_USB_SUPPORT=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/cobalt/patches-2.6.32/001-no_module_reloc.patch b/target/linux/cobalt/patches-2.6.32/001-no_module_reloc.patch new file mode 100644 index 000000000..d871dd137 --- /dev/null +++ b/target/linux/cobalt/patches-2.6.32/001-no_module_reloc.patch @@ -0,0 +1,371 @@ +diff -urN linux-2.6.32.7/arch/mips/Makefile linux-2.6.32.7.new/arch/mips/Makefile +--- linux-2.6.32.7/arch/mips/Makefile 2010-02-01 18:06:35.000000000 +0100 ++++ linux-2.6.32.7.new/arch/mips/Makefile 2010-01-29 00:06:20.000000000 +0100 +@@ -83,7 +83,7 @@ + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib +-MODFLAGS += -mno-long-calls ++MODFLAGS += -mlong-calls + + cflags-y += -ffreestanding + +diff -urN linux-2.6.32.7/arch/mips/include/asm/module.h linux-2.6.32.7.new/arch/mips/include/asm/module.h +--- linux-2.6.32.7/arch/mips/include/asm/module.h 2010-02-01 18:06:35.000000000 +0100 ++++ linux-2.6.32.7.new/arch/mips/include/asm/module.h 2010-01-29 00:06:20.000000000 +0100 +@@ -9,11 +9,6 @@ + struct list_head dbe_list; + const struct exception_table_entry *dbe_start; + const struct exception_table_entry *dbe_end; +- +- void *phys_plt_tbl; +- void *virt_plt_tbl; +- unsigned int phys_plt_offset; +- unsigned int virt_plt_offset; + }; + + typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ +diff -urN linux-2.6.32.7/arch/mips/kernel/module.c linux-2.6.32.7.new/arch/mips/kernel/module.c +--- linux-2.6.32.7/arch/mips/kernel/module.c 2010-02-01 18:06:35.000000000 +0100 ++++ linux-2.6.32.7.new/arch/mips/kernel/module.c 2010-01-29 00:06:20.000000000 +0100 +@@ -43,117 +43,6 @@ + static LIST_HEAD(dbe_list); + static DEFINE_SPINLOCK(dbe_lock); + +-/* +- * Get the potential max trampolines size required of the init and +- * non-init sections. Only used if we cannot find enough contiguous +- * physically mapped memory to put the module into. +- */ +-static unsigned int +-get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, +- const char *secstrings, unsigned int symindex, bool is_init) +-{ +- unsigned long ret = 0; +- unsigned int i, j; +- Elf_Sym *syms; +- +- /* Everything marked ALLOC (this includes the exported symbols) */ +- for (i = 1; i < hdr->e_shnum; ++i) { +- unsigned int info = sechdrs[i].sh_info; +- +- if (sechdrs[i].sh_type != SHT_REL +- && sechdrs[i].sh_type != SHT_RELA) +- continue; +- +- /* Not a valid relocation section? */ +- if (info >= hdr->e_shnum) +- continue; +- +- /* Don't bother with non-allocated sections */ +- if (!(sechdrs[info].sh_flags & SHF_ALLOC)) +- continue; +- +- /* If it's called *.init*, and we're not init, we're +- not interested */ +- if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) +- != is_init) +- continue; +- +- syms = (Elf_Sym *) sechdrs[symindex].sh_addr; +- if (sechdrs[i].sh_type == SHT_REL) { +- Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; +- unsigned int size = sechdrs[i].sh_size / sizeof(*rel); +- +- for (j = 0; j < size; ++j) { +- Elf_Sym *sym; +- +- if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) +- continue; +- +- sym = syms + ELF_MIPS_R_SYM(rel[j]); +- if (!is_init && sym->st_shndx != SHN_UNDEF) +- continue; +- +- ret += 4 * sizeof(int); +- } +- } else { +- Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; +- unsigned int size = sechdrs[i].sh_size / sizeof(*rela); +- +- for (j = 0; j < size; ++j) { +- Elf_Sym *sym; +- +- if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) +- continue; +- +- sym = syms + ELF_MIPS_R_SYM(rela[j]); +- if (!is_init && sym->st_shndx != SHN_UNDEF) +- continue; +- +- ret += 4 * sizeof(int); +- } +- } +- } +- +- return ret; +-} +- +-#ifndef MODULE_START +-static void *alloc_phys(unsigned long size) +-{ +- unsigned order; +- struct page *page; +- struct page *p; +- +- size = PAGE_ALIGN(size); +- order = get_order(size); +- +- page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | +- __GFP_THISNODE, order); +- if (!page) +- return NULL; +- +- split_page(page, order); +- +- for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p) +- __free_page(p); +- +- return page_address(page); +-} +-#endif +- +-static void free_phys(void *ptr, unsigned long size) +-{ +- struct page *page; +- struct page *end; +- +- page = virt_to_page(ptr); +- end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT); +- +- for (; page < end; ++page) +- __free_page(page); +-} +- +- + void *module_alloc(unsigned long size) + { + #ifdef MODULE_START +@@ -169,99 +58,21 @@ + + return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL); + #else +- void *ptr; +- + if (size == 0) + return NULL; +- +- ptr = alloc_phys(size); +- +- /* If we failed to allocate physically contiguous memory, +- * fall back to regular vmalloc. The module loader code will +- * create jump tables to handle long jumps */ +- if (!ptr) +- return vmalloc(size); +- +- return ptr; +-#endif +-} +- +-static inline bool is_phys_addr(void *ptr) +-{ +-#ifdef CONFIG_64BIT +- return (KSEGX((unsigned long)ptr) == CKSEG0); +-#else +- return (KSEGX(ptr) == KSEG0); ++ return vmalloc(size); + #endif + } + + /* Free memory returned from module_alloc */ + void module_free(struct module *mod, void *module_region) + { +- if (is_phys_addr(module_region)) { +- if (mod->module_init == module_region) +- free_phys(module_region, mod->init_size); +- else if (mod->module_core == module_region) +- free_phys(module_region, mod->core_size); +- else +- BUG(); +- } else { +- vfree(module_region); +- } +-} +- +-static void *__module_alloc(int size, bool phys) +-{ +- void *ptr; +- +- if (phys) +- ptr = kmalloc(size, GFP_KERNEL); +- else +- ptr = vmalloc(size); +- return ptr; +-} +- +-static void __module_free(void *ptr) +-{ +- if (is_phys_addr(ptr)) +- kfree(ptr); +- else +- vfree(ptr); ++ vfree(module_region); + } + + int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) + { +- unsigned int symindex = 0; +- unsigned int core_size, init_size; +- int i; +- +- for (i = 1; i < hdr->e_shnum; i++) +- if (sechdrs[i].sh_type == SHT_SYMTAB) +- symindex = i; +- +- core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false); +- init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true); +- +- mod->arch.phys_plt_offset = 0; +- mod->arch.virt_plt_offset = 0; +- mod->arch.phys_plt_tbl = NULL; +- mod->arch.virt_plt_tbl = NULL; +- +- if ((core_size + init_size) == 0) +- return 0; +- +- mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1); +- if (!mod->arch.phys_plt_tbl) +- return -ENOMEM; +- +- mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0); +- if (!mod->arch.virt_plt_tbl) { +- __module_free(mod->arch.phys_plt_tbl); +- mod->arch.phys_plt_tbl = NULL; +- return -ENOMEM; +- } +- + return 0; + } + +@@ -284,36 +95,28 @@ + return 0; + } + +-static Elf_Addr add_plt_entry_to(unsigned *plt_offset, +- void *start, Elf_Addr v) ++static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) + { +- unsigned *tramp = start + *plt_offset; +- *plt_offset += 4 * sizeof(int); +- +- /* adjust carry for addiu */ +- if (v & 0x00008000) +- v += 0x10000; +- +- tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ +- tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ +- tramp[2] = 0x03200008; /* jr t9 */ +- tramp[3] = 0x00000000; /* nop */ ++ if (v % 4) { ++ pr_err("module %s: dangerous R_MIPS_26 REL relocation\n", ++ me->name); ++ return -ENOEXEC; ++ } + +- return (Elf_Addr) tramp; +-} ++ if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { ++ printk(KERN_ERR ++ "module %s: relocation overflow\n", ++ me->name); ++ return -ENOEXEC; ++ } + +-static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) +-{ +- if (is_phys_addr(location)) +- return add_plt_entry_to(&me->arch.phys_plt_offset, +- me->arch.phys_plt_tbl, v); +- else +- return add_plt_entry_to(&me->arch.virt_plt_offset, +- me->arch.virt_plt_tbl, v); ++ *location = (*location & ~0x03ffffff) | ++ ((*location + (v >> 2)) & 0x03ffffff); + ++ return 0; + } + +-static int set_r_mips_26(struct module *me, u32 *location, u32 ofs, Elf_Addr v) ++static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v) + { + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n", +@@ -322,31 +125,17 @@ + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { +- v = add_plt_entry(me, location, v + (ofs << 2)); +- if (!v) { +- printk(KERN_ERR ++ printk(KERN_ERR + "module %s: relocation overflow\n", + me->name); +- return -ENOEXEC; +- } +- ofs = 0; ++ return -ENOEXEC; + } + +- *location = (*location & ~0x03ffffff) | ((ofs + (v >> 2)) & 0x03ffffff); ++ *location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff); + + return 0; + } + +-static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) +-{ +- return set_r_mips_26(me, location, *location & 0x03ffffff, v); +-} +- +-static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v) +-{ +- return set_r_mips_26(me, location, 0, v); +-} +- + static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v) + { + struct mips_hi16 *n; +@@ -611,32 +400,11 @@ + list_add(&me->arch.dbe_list, &dbe_list); + spin_unlock_irq(&dbe_lock); + } +- +- /* Get rid of the fixup trampoline if we're running the module +- * from physically mapped address space */ +- if (me->arch.phys_plt_offset == 0) { +- __module_free(me->arch.phys_plt_tbl); +- me->arch.phys_plt_tbl = NULL; +- } +- if (me->arch.virt_plt_offset == 0) { +- __module_free(me->arch.virt_plt_tbl); +- me->arch.virt_plt_tbl = NULL; +- } +- + return 0; + } + + void module_arch_cleanup(struct module *mod) + { +- if (mod->arch.phys_plt_tbl) { +- __module_free(mod->arch.phys_plt_tbl); +- mod->arch.phys_plt_tbl = NULL; +- } +- if (mod->arch.virt_plt_tbl) { +- __module_free(mod->arch.virt_plt_tbl); +- mod->arch.virt_plt_tbl = NULL; +- } +- + spin_lock_irq(&dbe_lock); + list_del(&mod->arch.dbe_list); + spin_unlock_irq(&dbe_lock); diff --git a/target/linux/config-2.6.30 b/target/linux/config-2.6.30 deleted file mode 100644 index 5054d158a..000000000 --- a/target/linux/config-2.6.30 +++ /dev/null @@ -1,269 +0,0 @@ -# CONFIG_32BIT is not set -CONFIG_64BIT=y -CONFIG_64BIT_PHYS_ADDR=y -# CONFIG_ALTERA_PCIE_CHDMA is not set -# CONFIG_ANDROID is not set -# CONFIG_ANDROID_BINDER_IPC is not set -# CONFIG_ANDROID_LOGGER is not set -# CONFIG_ANDROID_LOW_MEMORY_KILLER is not set -# CONFIG_ANDROID_RAM_CONSOLE is not set -# CONFIG_ARCH_HAS_ILOG2_U32 is not set -# CONFIG_ARCH_HAS_ILOG2_U64 is not set -CONFIG_ARCH_POPULATES_NODE_MAP=y -CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_ARCH_SUPPORTS_MSI=y -CONFIG_ARCH_SUPPORTS_OPROFILE=y -# CONFIG_ARPD is not set -# CONFIG_B3DFG is not set -# CONFIG_BACKTRACE_SELF_TEST is not set -# CONFIG_BCM47XX is not set -# CONFIG_BINARY_PRINTF is not set -CONFIG_BINFMT_ELF32=y -CONFIG_BITREVERSE=y -CONFIG_BLOCK_COMPAT=y -# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set -CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 -# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 -# CONFIG_BOOT_PRINTK_DELAY is not set -CONFIG_BSD_PROCESS_ACCT_V3=y -# CONFIG_CAVIUM_OCTEON_2ND_KERNEL is not set -CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE=2 -CONFIG_CAVIUM_OCTEON_HW_FIX_UNALIGNED=y -CONFIG_CAVIUM_OCTEON_LOCK_L2=y -CONFIG_CAVIUM_OCTEON_LOCK_L2_EXCEPTION=y -CONFIG_CAVIUM_OCTEON_LOCK_L2_INTERRUPT=y -CONFIG_CAVIUM_OCTEON_LOCK_L2_LOW_LEVEL_INTERRUPT=y -CONFIG_CAVIUM_OCTEON_LOCK_L2_MEMCPY=y -CONFIG_CAVIUM_OCTEON_LOCK_L2_TLB=y -CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD=y -# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set -CONFIG_CAVIUM_OCTEON_SPECIFIC_OPTIONS=y -CONFIG_CEVT_R4K=y -CONFIG_CEVT_R4K_LIB=y -# CONFIG_CGROUP_SCHED is not set -CONFIG_CMDLINE="console=ttyS0,115200" -# CONFIG_COMEDI is not set -CONFIG_COMPAT=y -CONFIG_COMPAT_BRK=y -CONFIG_CPU_BIG_ENDIAN=y -CONFIG_CPU_CAVIUM_OCTEON=y -CONFIG_CPU_HAS_PREFETCH=y -CONFIG_CPU_HAS_SYNC=y -# CONFIG_CPU_LITTLE_ENDIAN is not set -# CONFIG_CPU_LOONGSON2 is not set -# CONFIG_CPU_MIPS32_R1 is not set -# CONFIG_CPU_MIPS32_R2 is not set -# CONFIG_CPU_MIPS64_R1 is not set -# CONFIG_CPU_MIPS64_R2 is not set -CONFIG_CPU_MIPSR2=y -# CONFIG_CPU_NEVADA is not set -# CONFIG_CPU_R10000 is not set -# CONFIG_CPU_R3000 is not set -# CONFIG_CPU_R4300 is not set -# CONFIG_CPU_R4X00 is not set -# CONFIG_CPU_R5000 is not set -# CONFIG_CPU_R5432 is not set -# CONFIG_CPU_R5500 is not set -# CONFIG_CPU_R6000 is not set -# CONFIG_CPU_R8000 is not set -# CONFIG_CPU_RM7000 is not set -# CONFIG_CPU_RM9000 is not set -# CONFIG_CPU_SB1 is not set -CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_HIGHMEM=y -# CONFIG_CPU_TX39XX is not set -# CONFIG_CPU_TX49XX is not set -# CONFIG_CPU_VR41XX is not set -CONFIG_CRAMFS=y -# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -# CONFIG_DEBUG_DEVRES is not set -# CONFIG_DEBUG_DRIVER is not set -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_LIST is not set -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -# CONFIG_DEBUG_LOCK_ALLOC is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_NOTIFIERS is not set -# CONFIG_DEBUG_OBJECTS is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_DEBUG_SG is not set -# CONFIG_DEBUG_SHIRQ is not set -# CONFIG_DEBUG_SLAB is not set -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -# CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_DEBUG_VM is not set -# CONFIG_DEBUG_WRITECOUNT is not set -CONFIG_DECOMPRESS_LZMA=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_DETECT_SOFTLOCKUP=y -CONFIG_DEVKMEM=y -CONFIG_DEVPORT=y -# CONFIG_DM9000 is not set -CONFIG_DMA_COHERENT=y -CONFIG_DNOTIFY=y -# CONFIG_DST is not set -CONFIG_EARLY_PRINTK=y -# CONFIG_ECHO is not set -CONFIG_ELF_CORE=y -CONFIG_ENABLE_MUST_CHECK=y -# CONFIG_ET131X is not set -CONFIG_FAIR_GROUP_SCHED=y -# CONFIG_FAULT_INJECTION is not set -# CONFIG_FLATMEM_MANUAL is not set -CONFIG_FRAME_WARN=2048 -# CONFIG_FW_LOADER is not set -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -CONFIG_GENERIC_CMOS_UPDATE=y -CONFIG_GENERIC_FIND_LAST_BIT=y -CONFIG_GENERIC_FIND_NEXT_BIT=y -CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y -CONFIG_GROUP_SCHED=y -# CONFIG_HAMRADIO is not set -CONFIG_HARDWARE_WATCHPOINTS=y -CONFIG_HAS_DMA=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y -CONFIG_HAVE_ARCH_KGDB=y -# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set -CONFIG_HAVE_IDE=y -CONFIG_HAVE_MEMORY_PRESENT=y -CONFIG_HAVE_MLOCK=y -CONFIG_HAVE_MLOCKED_PAGE_BIT=y -CONFIG_HAVE_OPROFILE=y -CONFIG_HAVE_SYSCALL_WRAPPERS=y -# CONFIG_HECI is not set -# CONFIG_HIGH_RES_TIMERS is not set -CONFIG_HW_HAS_PCI=y -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_OCTEON=y -CONFIG_HZ=250 -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_INOTIFY=y -CONFIG_INOTIFY_USER=y -CONFIG_IRQ_CPU=y -CONFIG_IRQ_CPU_OCTEON=y -CONFIG_IRQ_PER_CPU=y -# CONFIG_ISDN is not set -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_ALL is not set -CONFIG_KEXEC=y -# CONFIG_KGDB is not set -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_LEMOTE_FULONG is not set -CONFIG_LOCK_KERNEL=y -# CONFIG_LOCK_STAT is not set -# CONFIG_MACH_ALCHEMY is not set -# CONFIG_MACH_DECSTATION is not set -# CONFIG_MACH_JAZZ is not set -# CONFIG_MACH_TX39XX is not set -# CONFIG_MACH_TX49XX is not set -# CONFIG_MACH_VR41XX is not set -CONFIG_MAGIC_SYSRQ=y -# CONFIG_ME4000 is not set -# CONFIG_MEILHAUS is not set -# CONFIG_MIKROTIK_RB532 is not set -CONFIG_MIPS=y -CONFIG_MIPS32_COMPAT=y -CONFIG_MIPS32_N32=y -CONFIG_MIPS32_O32=y -# CONFIG_MIPS_COBALT is not set -CONFIG_MIPS_L1_CACHE_SHIFT=7 -# CONFIG_MIPS_MACHINE is not set -# CONFIG_MIPS_MALTA is not set -CONFIG_MIPS_MT_DISABLED=y -# CONFIG_MIPS_MT_SMP is not set -# CONFIG_MIPS_MT_SMTC is not set -# CONFIG_MIPS_SIM is not set -# CONFIG_MISC_DEVICES is not set -# CONFIG_MTD_CFI_INTELEXT is not set -# CONFIG_MTD_COMPLEX_MAPPINGS is not set -CONFIG_MTD_PHYSMAP=y -# CONFIG_NETWORK_FILESYSTEMS is not set -# CONFIG_NO_IOPORT is not set -CONFIG_NR_CPUS=16 -CONFIG_NR_CPUS_DEFAULT_16=y -# CONFIG_NXP_STB220 is not set -# CONFIG_NXP_STB225 is not set -CONFIG_OCTEON_ETHERNET=y -CONFIG_OCTEON_MGMT=y -CONFIG_PAGEFLAGS_EXTENDED=y -# CONFIG_PAGE_POISONING is not set -# CONFIG_PARTITION_ADVANCED is not set -# CONFIG_PCI_DEBUG is not set -CONFIG_PCI_DOMAINS=y -CONFIG_PHYS_ADDR_T_64BIT=y -# CONFIG_PLAN9AUTH is not set -# CONFIG_PMC_MSP is not set -# CONFIG_PMC_YOSEMITE is not set -# CONFIG_PNX8550_JBS is not set -# CONFIG_PNX8550_STB810 is not set -# CONFIG_POHMELFS is not set -CONFIG_POSIX_MQUEUE=y -CONFIG_POSIX_MQUEUE_SYSCTL=y -# CONFIG_PROBE_INITRD_HEADER is not set -CONFIG_PROC_PAGE_MONITOR=y -# CONFIG_PROVE_LOCKING is not set -# CONFIG_RCU_TORTURE_TEST is not set -CONFIG_RELAY=y -# CONFIG_RTL8187SE is not set -# CONFIG_RT_GROUP_SCHED is not set -# CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_RUNTIME_DEBUG is not set -# CONFIG_SCHEDSTATS is not set -CONFIG_SCHED_DEBUG=y -CONFIG_SCHED_OMIT_FRAME_POINTER=y -# CONFIG_SCSI_DMA is not set -CONFIG_SECCOMP=y -# CONFIG_SERIAL_8250_EXTENDED is not set -# CONFIG_SGI_IP22 is not set -# CONFIG_SGI_IP27 is not set -# CONFIG_SGI_IP28 is not set -# CONFIG_SGI_IP32 is not set -# CONFIG_SIBYTE_BIGSUR is not set -# CONFIG_SIBYTE_CARMEL is not set -# CONFIG_SIBYTE_CRHINE is not set -# CONFIG_SIBYTE_CRHONE is not set -# CONFIG_SIBYTE_LITTLESUR is not set -# CONFIG_SIBYTE_RHONE is not set -# CONFIG_SIBYTE_SENTOSA is not set -# CONFIG_SIBYTE_SWARM is not set -# CONFIG_SLOW_WORK is not set -CONFIG_SMP=y -CONFIG_SPARSEMEM=y -CONFIG_SPARSEMEM_MANUAL=y -CONFIG_SPARSEMEM_STATIC=y -CONFIG_STAGING=y -# CONFIG_STAGING_EXCLUDE_BUILD is not set -CONFIG_STOP_MACHINE=y -CONFIG_SWAP_IO_SPACE=y -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_SYSVIPC_COMPAT=y -CONFIG_SYS_HAS_CPU_CAVIUM_OCTEON=y -CONFIG_SYS_HAS_EARLY_PRINTK=y -CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y -CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y -CONFIG_SYS_SUPPORTS_HIGHMEM=y -CONFIG_SYS_SUPPORTS_SMP=y -# CONFIG_TC35815 is not set -# CONFIG_TIMER_STATS is not set -CONFIG_TRACING_SUPPORT=y -CONFIG_UNEVICTABLE_LRU=y -CONFIG_USB_SUPPORT=y -CONFIG_USER_SCHED=y -CONFIG_USE_GENERIC_SMP_HELPERS=y -# CONFIG_VLAN_8021Q is not set -CONFIG_VM_EVENT_COUNTERS=y -CONFIG_WEAK_ORDERING=y -CONFIG_WEAK_REORDERING_BEYOND_LLSC=y -# CONFIG_WLAN_80211 is not set -CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/etraxi2c.h b/target/linux/etrax/files/arch/cris/arch-v10/drivers/etraxi2c.h similarity index 100% rename from target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/etraxi2c.h rename to target/linux/etrax/files/arch/cris/arch-v10/drivers/etraxi2c.h diff --git a/target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_errno.h b/target/linux/etrax/files/arch/cris/arch-v10/drivers/i2c_errno.h similarity index 100% rename from target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_errno.h rename to target/linux/etrax/files/arch/cris/arch-v10/drivers/i2c_errno.h diff --git a/target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_gvc.c b/target/linux/etrax/files/arch/cris/arch-v10/drivers/i2c_gvc.c similarity index 100% rename from target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_gvc.c rename to target/linux/etrax/files/arch/cris/arch-v10/drivers/i2c_gvc.c diff --git a/target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_gvc.h b/target/linux/etrax/files/arch/cris/arch-v10/drivers/i2c_gvc.h similarity index 100% rename from target/linux/etrax/files-2.6.30/arch/cris/arch-v10/drivers/i2c_gvc.h rename to target/linux/etrax/files/arch/cris/arch-v10/drivers/i2c_gvc.h diff --git a/target/linux/etrax/files-2.6.30/drivers/usb/host/hc-cris-dbg.h b/target/linux/etrax/files/drivers/usb/host/hc-cris-dbg.h similarity index 100% rename from target/linux/etrax/files-2.6.30/drivers/usb/host/hc-cris-dbg.h rename to target/linux/etrax/files/drivers/usb/host/hc-cris-dbg.h diff --git a/target/linux/etrax/files-2.6.30/drivers/usb/host/hc-crisv10.c b/target/linux/etrax/files/drivers/usb/host/hc-crisv10.c similarity index 100% rename from target/linux/etrax/files-2.6.30/drivers/usb/host/hc-crisv10.c rename to target/linux/etrax/files/drivers/usb/host/hc-crisv10.c diff --git a/target/linux/etrax/files-2.6.30/drivers/usb/host/hc-crisv10.h b/target/linux/etrax/files/drivers/usb/host/hc-crisv10.h similarity index 100% rename from target/linux/etrax/files-2.6.30/drivers/usb/host/hc-crisv10.h rename to target/linux/etrax/files/drivers/usb/host/hc-crisv10.h diff --git a/target/linux/generic-2.4/config-default b/target/linux/generic-2.4/config-default index 869e4f4cc..8490f36b3 100644 --- a/target/linux/generic-2.4/config-default +++ b/target/linux/generic-2.4/config-default @@ -203,6 +203,7 @@ CONFIG_IP6_NF_MATCH_OWNER=m CONFIG_IP6_NF_MATCH_RANDOM=m # CONFIG_IP6_NF_MATCH_RT is not set # CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_TARGET_IMQ=m CONFIG_IP6_NF_TARGET_LOG=m CONFIG_IP6_NF_TARGET_MARK=m @@ -277,6 +278,7 @@ CONFIG_IP_NF_NAT_SNMP_BASIC=m CONFIG_IP_NF_NAT_TFTP=m CONFIG_IP_NF_PPTP=m CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m CONFIG_IP_NF_RTSP=m CONFIG_IP_NF_SET_HASHSIZE=1024 CONFIG_IP_NF_SET_IPHASH=m @@ -297,6 +299,7 @@ CONFIG_IP_NF_TARGET_MARK=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_MIRROR=m CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_NOTRACK=m CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SET=m @@ -592,7 +595,7 @@ CONFIG_PPP_DEFLATE=m CONFIG_PPP_FILTER=y CONFIG_PPP=m CONFIG_PPP_MPPE_MPPC=m -# CONFIG_PPP_MULTILINK is not set +CONFIG_PPP_MULTILINK=y CONFIG_PPPOE=m CONFIG_PPP_SYNC_TTY=m # CONFIG_PRISM54 is not set diff --git a/target/linux/generic-2.4/patches/000-linux_mips.patch b/target/linux/generic-2.4/patches/000-linux_mips.patch index 5eeb65f8b..0def0d698 100644 --- a/target/linux/generic-2.4/patches/000-linux_mips.patch +++ b/target/linux/generic-2.4/patches/000-linux_mips.patch @@ -12318,7 +12318,7 @@ +module_exit(au1550spi_exit); --- a/drivers/char/Config.in +++ b/drivers/char/Config.in -@@ -320,14 +320,11 @@ fi +@@ -322,14 +322,11 @@ fi if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then bool 'Tadpole ANA H8 Support (OBSOLETE)' CONFIG_H8 fi @@ -12335,7 +12335,7 @@ fi if [ "$CONFIG_TOSHIBA_RBTX4927" = "y" -o "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then tristate 'Dallas DS1742 RTC support' CONFIG_DS1742 -@@ -390,6 +387,11 @@ if [ "$CONFIG_DRM" = "y" ]; then +@@ -392,6 +389,11 @@ if [ "$CONFIG_DRM" = "y" ]; then source drivers/char/drm/Config.in fi fi @@ -12347,7 +12347,7 @@ endmenu if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then -@@ -398,6 +400,7 @@ fi +@@ -400,6 +402,7 @@ fi if [ "$CONFIG_SOC_AU1X00" = "y" ]; then tristate ' Alchemy Au1x00 GPIO device support' CONFIG_AU1X00_GPIO tristate ' Au1000/ADS7846 touchscreen support' CONFIG_TS_AU1X00_ADS7846 @@ -23800,7 +23800,7 @@ printk("\n"); --- a/fs/proc/array.c +++ b/fs/proc/array.c -@@ -368,15 +368,15 @@ int proc_pid_stat(struct task_struct *ta +@@ -376,15 +376,15 @@ int proc_pid_stat(struct task_struct *ta task->cmin_flt, task->maj_flt, task->cmaj_flt, @@ -23821,7 +23821,7 @@ vsize, mm ? mm->rss : 0, /* you might want to shift this left 3 */ task->rlim[RLIMIT_RSS].rlim_cur, -@@ -615,14 +615,14 @@ int proc_pid_cpu(struct task_struct *tas +@@ -629,14 +629,14 @@ int proc_pid_cpu(struct task_struct *tas len = sprintf(buffer, "cpu %lu %lu\n", @@ -27677,23 +27677,23 @@ include $(TOPDIR)/drivers/bluetooth/Makefile.lib --- a/Makefile +++ b/Makefile -@@ -472,10 +472,11 @@ mrproper: clean archmrproper +@@ -476,10 +476,11 @@ mrproper: clean archmrproper $(MAKE) -C Documentation/DocBook mrproper distclean: mrproper - rm -f core `find . \( -not -type d \) -and \ - \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ - -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ -- -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags +- -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags cscope* + find . \( -not -type d \) -and \ + \( -name core -o -name '*.orig' -o -name '*.rej' \ + -o -name '*~' -o -name '*.bak' -o -name '#*#' \ + -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \ -+ -o -name TAGS -o -name tags \) -print | env -i xargs rm -f ++ -o -name TAGS -o -name tags -o -name 'cscope*' \) -print | env -i xargs rm -f backup: mrproper cd .. && tar cf - linux/ | gzip -9 > backup.gz -@@ -502,7 +503,7 @@ mandocs: +@@ -506,7 +507,7 @@ mandocs: $(MAKE) -C Documentation/DocBook man sums: diff --git a/target/linux/generic-2.4/patches/051-remove_pcmcia_modinst_compat.patch b/target/linux/generic-2.4/patches/051-remove_pcmcia_modinst_compat.patch index 1b5773677..41d7cbee5 100644 --- a/target/linux/generic-2.4/patches/051-remove_pcmcia_modinst_compat.patch +++ b/target/linux/generic-2.4/patches/051-remove_pcmcia_modinst_compat.patch @@ -1,6 +1,6 @@ --- a/Makefile +++ b/Makefile -@@ -431,18 +431,9 @@ else +@@ -435,18 +435,9 @@ else depmod_opts := -b $(INSTALL_MOD_PATH) -r endif .PHONY: _modinst_post diff --git a/target/linux/generic-2.4/patches/100-wireless-extension.patch b/target/linux/generic-2.4/patches/100-wireless-extension.patch index d6fc54987..a4eee2d87 100644 --- a/target/linux/generic-2.4/patches/100-wireless-extension.patch +++ b/target/linux/generic-2.4/patches/100-wireless-extension.patch @@ -912,7 +912,7 @@ err = copy_to_user(iwr->u.data.pointer, extra, extra_size); if (err) -@@ -1042,9 +1128,25 @@ void wireless_send_event(struct net_devi +@@ -1043,9 +1129,25 @@ void wireless_send_event(struct net_devi * One of the main advantage of centralising spy support here is that * it becomes much easier to improve and extend it without having to touch * the drivers. One example is the addition of the Spy-Threshold events. @@ -939,7 +939,7 @@ /*------------------------------------------------------------------*/ /* * Standard Wireless Handler : set Spy List -@@ -1054,16 +1156,26 @@ int iw_handler_set_spy(struct net_device +@@ -1055,16 +1157,26 @@ int iw_handler_set_spy(struct net_device union iwreq_data * wrqu, char * extra) { @@ -971,7 +971,7 @@ /* Are there are addresses to copy? */ if(wrqu->data.length > 0) { int i; -@@ -1089,13 +1201,14 @@ int iw_handler_set_spy(struct net_device +@@ -1090,13 +1202,14 @@ int iw_handler_set_spy(struct net_device spydata->spy_address[i][5]); #endif /* WE_SPY_DEBUG */ } @@ -989,7 +989,7 @@ } /*------------------------------------------------------------------*/ -@@ -1107,12 +1220,14 @@ int iw_handler_get_spy(struct net_device +@@ -1108,12 +1221,14 @@ int iw_handler_get_spy(struct net_device union iwreq_data * wrqu, char * extra) { @@ -1007,7 +1007,7 @@ wrqu->data.length = spydata->spy_number; /* Copy addresses. */ -@@ -1129,9 +1244,6 @@ int iw_handler_get_spy(struct net_device +@@ -1130,9 +1245,6 @@ int iw_handler_get_spy(struct net_device for(i = 0; i < spydata->spy_number; i++) spydata->spy_stat[i].updated = 0; return 0; @@ -1017,7 +1017,7 @@ } /*------------------------------------------------------------------*/ -@@ -1143,11 +1255,13 @@ int iw_handler_set_thrspy(struct net_dev +@@ -1144,11 +1256,13 @@ int iw_handler_set_thrspy(struct net_dev union iwreq_data * wrqu, char * extra) { @@ -1034,7 +1034,7 @@ /* Just do it */ memcpy(&(spydata->spy_thr_low), &(threshold->low), 2 * sizeof(struct iw_quality)); -@@ -1160,9 +1274,6 @@ int iw_handler_set_thrspy(struct net_dev +@@ -1161,9 +1275,6 @@ int iw_handler_set_thrspy(struct net_dev #endif /* WE_SPY_DEBUG */ return 0; @@ -1044,7 +1044,7 @@ } /*------------------------------------------------------------------*/ -@@ -1174,22 +1285,20 @@ int iw_handler_get_thrspy(struct net_dev +@@ -1175,22 +1286,20 @@ int iw_handler_get_thrspy(struct net_dev union iwreq_data * wrqu, char * extra) { @@ -1072,7 +1072,7 @@ /*------------------------------------------------------------------*/ /* * Prepare and send a Spy Threshold event -@@ -1227,7 +1336,6 @@ static void iw_send_thrspy_event(struct +@@ -1228,7 +1337,6 @@ static void iw_send_thrspy_event(struct /* Send event to user space */ wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); } @@ -1080,7 +1080,7 @@ /* ---------------------------------------------------------------- */ /* -@@ -1240,12 +1348,14 @@ void wireless_spy_update(struct net_devi +@@ -1241,12 +1349,14 @@ void wireless_spy_update(struct net_devi unsigned char * address, struct iw_quality * wstats) { @@ -1098,7 +1098,7 @@ #ifdef WE_SPY_DEBUG printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]); #endif /* WE_SPY_DEBUG */ -@@ -1257,7 +1367,7 @@ void wireless_spy_update(struct net_devi +@@ -1258,7 +1368,7 @@ void wireless_spy_update(struct net_devi sizeof(struct iw_quality)); match = i; } @@ -1107,7 +1107,7 @@ /* Generate an event if we cross the spy threshold. * To avoid event storms, we have a simple hysteresis : we generate * event only when we go under the low threshold or above the -@@ -1277,6 +1387,4 @@ void wireless_spy_update(struct net_devi +@@ -1278,6 +1388,4 @@ void wireless_spy_update(struct net_devi } } } diff --git a/target/linux/generic-2.4/patches/108-optional_aout_support.patch b/target/linux/generic-2.4/patches/108-optional_aout_support.patch index ff8c8cf30..2162b8818 100644 --- a/target/linux/generic-2.4/patches/108-optional_aout_support.patch +++ b/target/linux/generic-2.4/patches/108-optional_aout_support.patch @@ -149,7 +149,7 @@ CONFIG_ACPI_EFI=y --- a/arch/m68k/config.in +++ b/arch/m68k/config.in -@@ -99,6 +99,9 @@ if [ "$CONFIG_PROC_FS" = "y" ]; then +@@ -100,6 +100,9 @@ if [ "$CONFIG_PROC_FS" = "y" ]; then fi tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF diff --git a/target/linux/generic-2.4/patches/209-build_fixes.patch b/target/linux/generic-2.4/patches/209-build_fixes.patch index 5e76fd92b..720f0f3e5 100644 --- a/target/linux/generic-2.4/patches/209-build_fixes.patch +++ b/target/linux/generic-2.4/patches/209-build_fixes.patch @@ -9,7 +9,7 @@ (echo KERNELRELEASE \"$(KERNELRELEASE)\" exceeds $(uts_len) characters >&2; false) @echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver -@@ -503,7 +503,7 @@ dep-files: scripts/mkdep archdep include +@@ -507,7 +507,7 @@ dep-files: scripts/mkdep archdep include ifdef CONFIG_MODVERSIONS $(MAKE) update-modverfile endif diff --git a/target/linux/generic-2.4/patches/628-netfilter_raw.patch b/target/linux/generic-2.4/patches/628-netfilter_raw.patch new file mode 100644 index 000000000..de54a352d --- /dev/null +++ b/target/linux/generic-2.4/patches/628-netfilter_raw.patch @@ -0,0 +1,707 @@ +--- a/Documentation/Configure.help ++++ b/Documentation/Configure.help +@@ -3057,6 +3057,34 @@ CONFIG_IP_NF_FILTER + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++raw table support (required for NOTRACK/TRACE) ++CONFIG_IP_NF_RAW ++ This option adds a `raw' table to iptables. This table is the very ++ first in the netfilter framework and hooks in at the PREROUTING ++ and OUTPUT chains. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++NOTRACK target support ++CONFIG_IP_NF_TARGET_NOTRACK ++ The NOTRACK target allows a select rule to specify ++ which packets *not* to enter the conntrack/NAT ++ subsystem with all the consequences (no ICMP error tracking, ++ no protocol helpers for the selected packets). ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++raw table support (required for TRACE) ++CONFIG_IP6_NF_RAW ++ This option adds a `raw' table to ip6tables. This table is the very ++ first in the netfilter framework and hooks in at the PREROUTING ++ and OUTPUT chains. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ + REJECT target support + CONFIG_IP_NF_TARGET_REJECT + The REJECT target allows a filtering rule to specify that an ICMP +--- a/include/linux/netfilter_ipv4/ip_conntrack.h ++++ b/include/linux/netfilter_ipv4/ip_conntrack.h +@@ -286,6 +286,9 @@ extern void ip_ct_refresh_acct(struct ip + /* Call me when a conntrack is destroyed. */ + extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack); + ++/* Fake conntrack entry for untracked connections */ ++extern struct ip_conntrack ip_conntrack_untracked; ++ + /* Returns new sk_buff, or NULL */ + struct sk_buff * + ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user); +--- a/include/linux/netfilter_ipv4/ipt_conntrack.h ++++ b/include/linux/netfilter_ipv4/ipt_conntrack.h +@@ -10,6 +10,7 @@ + + #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1)) + #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2)) ++#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3)) + + /* flags, invflags: */ + #define IPT_CONNTRACK_STATE 0x01 +--- a/include/linux/netfilter_ipv4/ipt_state.h ++++ b/include/linux/netfilter_ipv4/ipt_state.h +@@ -4,6 +4,8 @@ + #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1)) + #define IPT_STATE_INVALID (1 << 0) + ++#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1)) ++ + struct ipt_state_info + { + unsigned int statemask; +--- a/include/linux/netfilter_ipv4.h ++++ b/include/linux/netfilter_ipv4.h +@@ -51,6 +51,8 @@ + + enum nf_ip_hook_priorities { + NF_IP_PRI_FIRST = INT_MIN, ++ NF_IP_PRI_CONNTRACK_DEFRAG = -400, ++ NF_IP_PRI_RAW = -300, + NF_IP_PRI_CONNTRACK = -200, + NF_IP_PRI_MANGLE = -150, + NF_IP_PRI_NAT_DST = -100, +--- a/net/ipv4/netfilter/Config.in ++++ b/net/ipv4/netfilter/Config.in +@@ -153,6 +153,15 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; + dep_tristate ' TTL target support' CONFIG_IP_NF_TARGET_TTL $CONFIG_IP_NF_IPTABLES + dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES + dep_tristate ' TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ tristate ' raw table support (required for NOTRACK/TRACE)' CONFIG_IP_NF_RAW $CONFIG_IP_NF_IPTABLES ++ fi ++ if [ "$CONFIG_IP_NF_RAW" != "n" ]; then ++ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then ++ dep_tristate ' NOTRACK target support' CONFIG_IP_NF_TARGET_NOTRACK $CONFIG_IP_NF_RAW ++ fi ++ # Marker for TRACE target ++ fi + fi + + tristate 'ARP tables support' CONFIG_IP_NF_ARPTABLES +--- a/net/ipv4/netfilter/ip_conntrack_core.c ++++ b/net/ipv4/netfilter/ip_conntrack_core.c +@@ -64,6 +64,7 @@ int ip_conntrack_max = 0; + static atomic_t ip_conntrack_count = ATOMIC_INIT(0); + struct list_head *ip_conntrack_hash; + static kmem_cache_t *ip_conntrack_cachep; ++struct ip_conntrack ip_conntrack_untracked; + static LIST_HEAD(unconfirmed); + + extern struct ip_conntrack_protocol ip_conntrack_generic_protocol; +@@ -834,6 +835,15 @@ unsigned int ip_conntrack_in(unsigned in + int set_reply; + int ret; + ++ /* Never happen */ ++ if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) { ++ if (net_ratelimit()) { ++ printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n", ++ (*pskb)->nh.iph->protocol, hooknum); ++ } ++ return NF_DROP; ++ } ++ + /* FIXME: Do this right please. --RR */ + (*pskb)->nfcache |= NFC_UNKNOWN; + +@@ -1489,6 +1499,18 @@ int __init ip_conntrack_init(void) + + /* For use by ipt_REJECT */ + ip_ct_attach = ip_conntrack_attach; ++ ++ /* Set up fake conntrack: ++ - to never be deleted, not in any hashes */ ++ atomic_set(&ip_conntrack_untracked.ct_general.use, 1); ++ /* - and look it like as a confirmed connection */ ++ set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status); ++ /* - and prepare the ctinfo field for REJECT/NAT. */ ++ ip_conntrack_untracked.infos[IP_CT_NEW].master = ++ ip_conntrack_untracked.infos[IP_CT_RELATED].master = ++ ip_conntrack_untracked.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master = ++ &ip_conntrack_untracked.ct_general; ++ + return ret; + + err_free_hash: +--- a/net/ipv4/netfilter/ip_conntrack_standalone.c ++++ b/net/ipv4/netfilter/ip_conntrack_standalone.c +@@ -218,6 +218,29 @@ static unsigned int ip_confirm(unsigned + return ip_conntrack_confirm(*pskb); + } + ++static unsigned int ip_conntrack_defrag(unsigned int hooknum, ++ struct sk_buff **pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ /* Previously seen (loopback)? Ignore. Do this before ++ fragment check. */ ++ if ((*pskb)->nfct) ++ return NF_ACCEPT; ++ ++ /* Gather fragments. */ ++ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { ++ *pskb = ip_ct_gather_frags(*pskb, ++ hooknum == NF_IP_PRE_ROUTING ? ++ IP_DEFRAG_CONNTRACK_IN : ++ IP_DEFRAG_CONNTRACK_OUT); ++ if (!*pskb) ++ return NF_STOLEN; ++ } ++ return NF_ACCEPT; ++} ++ + static unsigned int ip_refrag(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, +@@ -259,9 +282,15 @@ static unsigned int ip_conntrack_local(u + + /* Connection tracking may drop packets, but never alters them, so + make it the first hook. */ ++static struct nf_hook_ops ip_conntrack_defrag_ops ++= { { NULL, NULL }, ip_conntrack_defrag, PF_INET, NF_IP_PRE_ROUTING, ++ NF_IP_PRI_CONNTRACK_DEFRAG }; + static struct nf_hook_ops ip_conntrack_in_ops + = { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_PRE_ROUTING, + NF_IP_PRI_CONNTRACK }; ++static struct nf_hook_ops ip_conntrack_defrag_local_out_ops ++= { { NULL, NULL }, ip_conntrack_defrag, PF_INET, NF_IP_LOCAL_OUT, ++ NF_IP_PRI_CONNTRACK_DEFRAG }; + static struct nf_hook_ops ip_conntrack_local_out_ops + = { { NULL, NULL }, ip_conntrack_local, PF_INET, NF_IP_LOCAL_OUT, + NF_IP_PRI_CONNTRACK }; +@@ -382,10 +411,20 @@ static int init_or_cleanup(int init) + if (!proc) goto cleanup_init; + proc->owner = THIS_MODULE; + ++ ret = nf_register_hook(&ip_conntrack_defrag_ops); ++ if (ret < 0) { ++ printk("ip_conntrack: can't register pre-routing defrag hook.\n"); ++ goto cleanup_proc; ++ } ++ ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops); ++ if (ret < 0) { ++ printk("ip_conntrack: can't register local_out defrag hook.\n"); ++ goto cleanup_defragops; ++ } + ret = nf_register_hook(&ip_conntrack_in_ops); + if (ret < 0) { + printk("ip_conntrack: can't register pre-routing hook.\n"); +- goto cleanup_proc; ++ goto cleanup_defraglocalops; + } + ret = nf_register_hook(&ip_conntrack_local_out_ops); + if (ret < 0) { +@@ -423,6 +462,10 @@ static int init_or_cleanup(int init) + nf_unregister_hook(&ip_conntrack_local_out_ops); + cleanup_inops: + nf_unregister_hook(&ip_conntrack_in_ops); ++ cleanup_defraglocalops: ++ nf_unregister_hook(&ip_conntrack_defrag_local_out_ops); ++ cleanup_defragops: ++ nf_unregister_hook(&ip_conntrack_defrag_ops); + cleanup_proc: + proc_net_remove("ip_conntrack"); + cleanup_init: +@@ -512,5 +555,6 @@ EXPORT_SYMBOL(ip_conntrack_htable_size); + EXPORT_SYMBOL(ip_conntrack_expect_list); + EXPORT_SYMBOL(ip_conntrack_lock); + EXPORT_SYMBOL(ip_conntrack_hash); ++EXPORT_SYMBOL(ip_conntrack_untracked); + EXPORT_SYMBOL_GPL(ip_conntrack_find_get); + EXPORT_SYMBOL_GPL(ip_conntrack_put); +--- a/net/ipv4/netfilter/ip_nat_core.c ++++ b/net/ipv4/netfilter/ip_nat_core.c +@@ -1023,6 +1023,10 @@ int __init ip_nat_init(void) + /* FIXME: Man, this is a hack. */ + IP_NF_ASSERT(ip_conntrack_destroyed == NULL); + ip_conntrack_destroyed = &ip_nat_cleanup_conntrack; ++ ++ /* Initialize fake conntrack so that NAT will skip it */ ++ ip_conntrack_untracked.nat.info.initialized |= ++ (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST); + + return 0; + } +--- /dev/null ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -0,0 +1,149 @@ ++/* ++ * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT . ++ * ++ * Copyright (C) 2003 Jozsef Kadlecsik ++ */ ++#include ++#include ++ ++#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT)) ++ ++/* Standard entry. */ ++struct ipt_standard ++{ ++ struct ipt_entry entry; ++ struct ipt_standard_target target; ++}; ++ ++struct ipt_error_target ++{ ++ struct ipt_entry_target target; ++ char errorname[IPT_FUNCTION_MAXNAMELEN]; ++}; ++ ++struct ipt_error ++{ ++ struct ipt_entry entry; ++ struct ipt_error_target target; ++}; ++ ++static struct ++{ ++ struct ipt_replace repl; ++ struct ipt_standard entries[2]; ++ struct ipt_error term; ++} initial_table __initdata ++= { { "raw", RAW_VALID_HOOKS, 3, ++ sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error), ++ { [NF_IP_PRE_ROUTING] 0, ++ [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) }, ++ { [NF_IP_PRE_ROUTING] 0, ++ [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) }, ++ 0, NULL, { } }, ++ { ++ /* PRE_ROUTING */ ++ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ipt_entry), ++ sizeof(struct ipt_standard), ++ 0, { 0, 0 }, { } }, ++ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, ++ -NF_ACCEPT - 1 } }, ++ /* LOCAL_OUT */ ++ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ipt_entry), ++ sizeof(struct ipt_standard), ++ 0, { 0, 0 }, { } }, ++ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, ++ -NF_ACCEPT - 1 } } ++ }, ++ /* ERROR */ ++ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ipt_entry), ++ sizeof(struct ipt_error), ++ 0, { 0, 0 }, { } }, ++ { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, ++ { } }, ++ "ERROR" ++ } ++ } ++}; ++ ++static struct ipt_table packet_raw = { ++ .name = "raw", ++ .table = &initial_table.repl, ++ .valid_hooks = RAW_VALID_HOOKS, ++ .lock = RW_LOCK_UNLOCKED, ++ .me = THIS_MODULE ++}; ++ ++/* The work comes in here from netfilter.c. */ ++static unsigned int ++ipt_hook(unsigned int hook, ++ struct sk_buff **pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL); ++} ++ ++/* 'raw' is the very first table. */ ++static struct nf_hook_ops ipt_ops[] = { ++ { ++ .hook = ipt_hook, ++ .pf = PF_INET, ++ .hooknum = NF_IP_PRE_ROUTING, ++ .priority = NF_IP_PRI_RAW ++ }, ++ { ++ .hook = ipt_hook, ++ .pf = PF_INET, ++ .hooknum = NF_IP_LOCAL_OUT, ++ .priority = NF_IP_PRI_RAW ++ }, ++}; ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ /* Register table */ ++ ret = ipt_register_table(&packet_raw); ++ if (ret < 0) ++ return ret; ++ ++ /* Register hooks */ ++ ret = nf_register_hook(&ipt_ops[0]); ++ if (ret < 0) ++ goto cleanup_table; ++ ++ ret = nf_register_hook(&ipt_ops[1]); ++ if (ret < 0) ++ goto cleanup_hook0; ++ ++ return ret; ++ ++ cleanup_hook0: ++ nf_unregister_hook(&ipt_ops[0]); ++ cleanup_table: ++ ipt_unregister_table(&packet_raw); ++ ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++) ++ nf_unregister_hook(&ipt_ops[i]); ++ ++ ipt_unregister_table(&packet_raw); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +--- a/net/ipv4/netfilter/ipt_conntrack.c ++++ b/net/ipv4/netfilter/ipt_conntrack.c +@@ -27,11 +27,13 @@ match(const struct sk_buff *skb, + + #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) + +- if (ct) +- statebit = IPT_CONNTRACK_STATE_BIT(ctinfo); +- else +- statebit = IPT_CONNTRACK_STATE_INVALID; +- ++ if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW]) ++ statebit = IPT_CONNTRACK_STATE_UNTRACKED; ++ else if (ct) ++ statebit = IPT_CONNTRACK_STATE_BIT(ctinfo); ++ else ++ statebit = IPT_CONNTRACK_STATE_INVALID; ++ + if(sinfo->flags & IPT_CONNTRACK_STATE) { + if (ct) { + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != +--- /dev/null ++++ b/net/ipv4/netfilter/ipt_NOTRACK.c +@@ -0,0 +1,75 @@ ++/* This is a module which is used for setting up fake conntracks ++ * on packets so that they are not seen by the conntrack/NAT code. ++ */ ++#include ++#include ++ ++#include ++#include ++ ++static unsigned int ++target(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *targinfo, ++ void *userinfo) ++{ ++ /* Previously seen (loopback)? Ignore. */ ++ if ((*pskb)->nfct != NULL) ++ return IPT_CONTINUE; ++ ++ /* Attach fake conntrack entry. ++ If there is a real ct entry correspondig to this packet, ++ it'll hang aroun till timing out. We don't deal with it ++ for performance reasons. JK */ ++ (*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW]; ++ nf_conntrack_get((*pskb)->nfct); ++ ++ return IPT_CONTINUE; ++} ++ ++static int ++checkentry(const char *tablename, ++ const struct ipt_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ if (targinfosize != 0) { ++ printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n", ++ targinfosize); ++ return 0; ++ } ++ ++ if (strcmp(tablename, "raw") != 0) { ++ printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_notrack_reg = { ++ .name = "NOTRACK", ++ .target = target, ++ .checkentry = checkentry, ++ .me = THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ if (ipt_register_target(&ipt_notrack_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_notrack_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +--- a/net/ipv4/netfilter/ipt_state.c ++++ b/net/ipv4/netfilter/ipt_state.c +@@ -21,7 +21,9 @@ match(const struct sk_buff *skb, + enum ip_conntrack_info ctinfo; + unsigned int statebit; + +- if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) ++ if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW]) ++ statebit = IPT_STATE_UNTRACKED; ++ else if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) + statebit = IPT_STATE_INVALID; + else + statebit = IPT_STATE_BIT(ctinfo); +--- a/net/ipv4/netfilter/Makefile ++++ b/net/ipv4/netfilter/Makefile +@@ -77,6 +77,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_table + obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o + obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o + obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o ++obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o + + # matches + obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o +@@ -131,6 +132,7 @@ obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += i + obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o + obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o + obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o ++obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o + + # generic ARP tables + obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o +--- a/net/ipv6/netfilter/Config.in ++++ b/net/ipv6/netfilter/Config.in +@@ -79,6 +79,10 @@ if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; + dep_tristate ' IMQ target support' CONFIG_IP6_NF_TARGET_IMQ $CONFIG_IP6_NF_MANGLE + fi + #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ tristate ' raw table support (required for TRACE)' CONFIG_IP6_NF_RAW $CONFIG_IP6_NF_IPTABLES ++ fi ++ # Marker for TRACE target + fi + + endmenu +--- /dev/null ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -0,0 +1,154 @@ ++/* ++ * IPv6 raw table, a port of the IPv4 raw table to IPv6 ++ * ++ * Copyright (C) 2003 Jozsef Kadlecsik ++ */ ++#include ++#include ++ ++#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT)) ++ ++#if 0 ++#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args) ++#else ++#define DEBUGP(x, args...) ++#endif ++ ++/* Standard entry. */ ++struct ip6t_standard ++{ ++ struct ip6t_entry entry; ++ struct ip6t_standard_target target; ++}; ++ ++struct ip6t_error_target ++{ ++ struct ip6t_entry_target target; ++ char errorname[IP6T_FUNCTION_MAXNAMELEN]; ++}; ++ ++struct ip6t_error ++{ ++ struct ip6t_entry entry; ++ struct ip6t_error_target target; ++}; ++ ++static struct ++{ ++ struct ip6t_replace repl; ++ struct ip6t_standard entries[2]; ++ struct ip6t_error term; ++} initial_table __initdata ++= { { "raw", RAW_VALID_HOOKS, 3, ++ sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error), ++ { [NF_IP6_PRE_ROUTING] 0, ++ [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) }, ++ { [NF_IP6_PRE_ROUTING] 0, ++ [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) }, ++ 0, NULL, { } }, ++ { ++ /* PRE_ROUTING */ ++ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ip6t_entry), ++ sizeof(struct ip6t_standard), ++ 0, { 0, 0 }, { } }, ++ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, ++ -NF_ACCEPT - 1 } }, ++ /* LOCAL_OUT */ ++ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ip6t_entry), ++ sizeof(struct ip6t_standard), ++ 0, { 0, 0 }, { } }, ++ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, ++ -NF_ACCEPT - 1 } }, ++ }, ++ /* ERROR */ ++ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ip6t_entry), ++ sizeof(struct ip6t_error), ++ 0, { 0, 0 }, { } }, ++ { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, ++ { } }, ++ "ERROR" ++ } ++ } ++}; ++ ++static struct ip6t_table packet_raw = { ++ .name = "raw", ++ .table = &initial_table.repl, ++ .valid_hooks = RAW_VALID_HOOKS, ++ .lock = RW_LOCK_UNLOCKED, ++ .me = THIS_MODULE ++}; ++ ++/* The work comes in here from netfilter.c. */ ++static unsigned int ++ip6t_hook(unsigned int hook, ++ struct sk_buff **pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL); ++} ++ ++static struct nf_hook_ops ip6t_ops[] = { ++ { ++ .hook = ip6t_hook, ++ .pf = PF_INET6, ++ .hooknum = NF_IP6_PRE_ROUTING, ++ .priority = NF_IP6_PRI_FIRST ++ }, ++ { ++ .hook = ip6t_hook, ++ .pf = PF_INET6, ++ .hooknum = NF_IP6_LOCAL_OUT, ++ .priority = NF_IP6_PRI_FIRST ++ }, ++}; ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ /* Register table */ ++ ret = ip6t_register_table(&packet_raw); ++ if (ret < 0) ++ return ret; ++ ++ /* Register hooks */ ++ ret = nf_register_hook(&ip6t_ops[0]); ++ if (ret < 0) ++ goto cleanup_table; ++ ++ ret = nf_register_hook(&ip6t_ops[1]); ++ if (ret < 0) ++ goto cleanup_hook0; ++ ++ return ret; ++ ++ cleanup_hook0: ++ nf_unregister_hook(&ip6t_ops[0]); ++ cleanup_table: ++ ip6t_unregister_table(&packet_raw); ++ ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) ++ nf_unregister_hook(&ip6t_ops[i]); ++ ++ ip6t_unregister_table(&packet_raw); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +--- a/net/ipv6/netfilter/Makefile ++++ b/net/ipv6/netfilter/Makefile +@@ -32,6 +32,7 @@ obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t + obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o + obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o + obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o ++obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o + obj-$(CONFIG_IP6_NF_MATCH_RANDOM) += ip6t_random.o + obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o + obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o diff --git a/target/linux/generic-2.6/config-2.6.25 b/target/linux/generic-2.6/config-2.6.25 index b544fe448..3ee990432 100644 --- a/target/linux/generic-2.6/config-2.6.25 +++ b/target/linux/generic-2.6/config-2.6.25 @@ -758,7 +758,7 @@ CONFIG_JOLIET=y CONFIG_KMOD=y # CONFIG_LAPB is not set # CONFIG_LASAT is not set -# CONFIG_LBD is not set +CONFIG_LBD=y # CONFIG_LDM_PARTITION is not set CONFIG_LEDS_CLASS=y CONFIG_LEDS_TRIGGER_DEFAULT_ON=y @@ -1073,11 +1073,11 @@ CONFIG_NFSD_TCP=y # CONFIG_NFSD_V2_ACL is not set # CONFIG_NFSD_V3_ACL is not set CONFIG_NFSD_V3=y -CONFIG_NFSD_V4=y +# CONFIG_NFSD_V4 is not set # CONFIG_NFS_FS is not set # CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V3=y -CONFIG_NFS_V4=y +# CONFIG_NFS_V4 is not set # CONFIG_NFTL is not set # CONFIG_NLS_ASCII is not set # CONFIG_NLS_CODEPAGE_1250 is not set diff --git a/target/linux/generic-2.6/config-2.6.30 b/target/linux/generic-2.6/config-2.6.30 index 9130ce6a5..72675e039 100644 --- a/target/linux/generic-2.6/config-2.6.30 +++ b/target/linux/generic-2.6/config-2.6.30 @@ -124,6 +124,7 @@ CONFIG_ATM_CLIP_NO_ICMP=y # CONFIG_B43LEGACY is not set # CONFIG_B44 is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKTRACE_SELF_TEST is not set CONFIG_BASE_FULL=y CONFIG_BASE_SMALL=0 # CONFIG_BASLER_EXCITE is not set @@ -143,6 +144,7 @@ CONFIG_BCM43XX_DMA=y # CONFIG_BCM43XX is not set # CONFIG_BCM43XX_PIO_MODE is not set CONFIG_BCM43XX_PIO=y +# CONFIG_BDI_SWITCH is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_BINFMT_AOUT is not set @@ -161,11 +163,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_BLK_DEV_CMD64X is not set # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5520 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_CS5535 is not set # CONFIG_BLK_DEV_CS5536 is not set -# CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_DELKIN is not set # CONFIG_BLK_DEV_FD is not set @@ -223,6 +225,7 @@ CONFIG_BLK_DEV=y CONFIG_BLOCK=y # CONFIG_BNX2 is not set # CONFIG_BONDING is not set +# CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_BOOT_TRACER is not set # CONFIG_BPQETHER is not set # CONFIG_BRIDGE_EBT_802_3 is not set @@ -315,6 +318,7 @@ CONFIG_CLS_U32_MARK=y CONFIG_CLS_U32_PERF=y CONFIG_CMDLINE="" # CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set # CONFIG_COMPAT_BRK is not set CONFIG_COMPAT_NET_DEV_OPS=y # CONFIG_CONFIGFS_FS is not set @@ -405,10 +409,36 @@ CONFIG_CRYPTO_ZLIB=y # CONFIG_DAB is not set # CONFIG_DAVICOM_PHY is not set # CONFIG_DCB is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_ERRORS is not set CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set # CONFIG_DECNET is not set CONFIG_DECOMPRESS_LZMA_NEEDED=y # CONFIG_DEFAULT_AS is not set @@ -425,6 +455,8 @@ CONFIG_DEFAULT_TCP_CONG="westwood" # CONFIG_DEFAULT_VEGAS is not set CONFIG_DEFAULT_WESTWOOD=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DETECT_SOFTLOCKUP is not set # CONFIG_DEVKMEM is not set # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_DGRS is not set @@ -481,12 +513,14 @@ CONFIG_EXPERIMENTAL=y # CONFIG_EXT3_FS_XATTR is not set # CONFIG_EXT4DEV_FS is not set # CONFIG_EXT4_FS is not set +# CONFIG_EXT4DEV_COMPAT is not set CONFIG_EXTRA_FIRMWARE="" CONFIG_EXTRA_TARGETS="" # CONFIG_FAIR_GROUP_SCHED is not set CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_FAT_FS is not set +# CONFIG_FAULT_INJECTION is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_ARC is not set # CONFIG_FB_ARK is not set @@ -568,6 +602,7 @@ CONFIG_FRAME_WARN=1024 # CONFIG_FTL is not set # CONFIG_FTRACE is not set # CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set # CONFIG_FUNCTION_TRACER is not set # CONFIG_FUSE_FS is not set # CONFIG_FUSION_FC is not set @@ -1005,6 +1040,7 @@ CONFIG_JOLIET=y CONFIG_KERNEL_LZMA=y # CONFIG_KEXEC is not set # CONFIG_KEYS is not set +# CONFIG_KGDB is not set # CONFIG_KMEMTRACE is not set CONFIG_KMOD=y # CONFIG_KPROBES is not set @@ -1012,7 +1048,7 @@ CONFIG_KMOD=y # CONFIG_LAPB is not set # CONFIG_LASAT is not set # CONFIG_LATENCYTOP is not set -# CONFIG_LBD is not set +CONFIG_LBD=y # CONFIG_LCD_LTV350QV is not set # CONFIG_LCD_TDO24M is not set # CONFIG_LCD_VGG2432A4 is not set @@ -1055,6 +1091,7 @@ CONFIG_LOCALVERSION="" CONFIG_LOCKDEP_SUPPORT=y # CONFIG_LOCKD is not set CONFIG_LOCKD_V4=y +# CONFIG_LOCK_STAT is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_LOGIRUMBLEPAD2_FF is not set # CONFIG_LOGITECH_FF is not set @@ -1132,6 +1169,7 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_MOUSE_PC110PAD is not set # CONFIG_MSDOS_FS is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set # CONFIG_MTD_ABSENT is not set # CONFIG_MTD_AFS_PARTS is not set # CONFIG_MTD_ALAUDA is not set @@ -1405,11 +1443,11 @@ CONFIG_NFSD_TCP=y # CONFIG_NFSD_V2_ACL is not set # CONFIG_NFSD_V3_ACL is not set CONFIG_NFSD_V3=y -CONFIG_NFSD_V4=y +# CONFIG_NFSD_V4 is not set # CONFIG_NFS_FS is not set # CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V3=y -CONFIG_NFS_V4=y +# CONFIG_NFS_V4 is not set # CONFIG_NFTL is not set # CONFIG_NILFS2_FS is not set CONFIG_NL80211=y @@ -1478,6 +1516,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_P54_COMMON is not set CONFIG_PACKET_MMAP=y CONFIG_PACKET=y +# CONFIG_PAGE_POISONING is not set # CONFIG_PAGE_SIZE_16KB is not set # CONFIG_PAGE_SIZE_32KB is not set CONFIG_PAGE_SIZE_4KB=y @@ -1493,11 +1532,11 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_PATA_ATIIXP is not set # CONFIG_PATA_CMD640_PCI is not set # CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CYPRESS is not set # CONFIG_PATA_CS5520 is not set # CONFIG_PATA_CS5530 is not set # CONFIG_PATA_CS5535 is not set # CONFIG_PATA_CS5536 is not set -# CONFIG_PATA_CYPRESS is not set # CONFIG_PATA_EFAR is not set # CONFIG_PATA_HPT366 is not set # CONFIG_PATA_HPT37X is not set @@ -1538,6 +1577,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_PCF8575 is not set # CONFIG_PCI200SYN is not set # CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_DEBUG is not set # CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set # CONFIG_PCIEASPM is not set # CONFIG_PCI_HERMES is not set @@ -1611,6 +1651,7 @@ CONFIG_PROC_KCORE=y # CONFIG_PROC_PAGE_MONITOR is not set CONFIG_PROC_SYSCTL=y # CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set # CONFIG_QEMU is not set # CONFIG_QLA3XXX is not set # CONFIG_QNX4FS_FS is not set @@ -1638,6 +1679,7 @@ CONFIG_PROC_SYSCTL=y CONFIG_RAMFS=y # CONFIG_RAW_DRIVER is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_RCU_TORTURE_TEST is not set # CONFIG_RD_BZIP2 is not set # CONFIG_RD_GZIP is not set CONFIG_RD_LZMA=y @@ -1710,7 +1752,10 @@ CONFIG_RTC_LIB=y # CONFIG_RTL8366_SMI is not set # CONFIG_RTL8366S_PHY_DEBUG_FS is not set # CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366RB_PHY is not set CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_RUNTIME_DEBUG is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_S2IO is not set # CONFIG_SAMPLES is not set @@ -1733,6 +1778,8 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_SCC is not set # CONFIG_SCHED_BFS is not set CONFIG_SCHED_CFS=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set # CONFIG_SCHED_TRACER is not set # CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_7000FASST is not set @@ -2470,12 +2517,12 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_VIDEO_CAFE_CCIC is not set # CONFIG_VIDEO_CAPTURE_DRIVERS is not set # CONFIG_VIDEO_CPIA is not set -# CONFIG_VIDEO_CS5345 is not set -# CONFIG_VIDEO_CS53L32A is not set # CONFIG_VIDEO_CX231XX is not set # CONFIG_VIDEO_CX2341X is not set # CONFIG_VIDEO_CX25840 is not set # CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set # CONFIG_VIDEO_DEV is not set # CONFIG_VIDEO_DPC is not set # CONFIG_VIDEO_EM28XX is not set @@ -2591,6 +2638,7 @@ CONFIG_XFRM=y # CONFIG_XFS_RT is not set # CONFIG_XFS_SECURITY is not set # CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set # CONFIG_YAFFS_FS is not set # CONFIG_YAM is not set # CONFIG_YELLOWFIN is not set diff --git a/target/linux/generic-2.6/config-2.6.31 b/target/linux/generic-2.6/config-2.6.31 index 6678ecc01..350f364c9 100644 --- a/target/linux/generic-2.6/config-2.6.31 +++ b/target/linux/generic-2.6/config-2.6.31 @@ -1049,8 +1049,7 @@ CONFIG_KMOD=y # CONFIG_LAPB is not set # CONFIG_LASAT is not set # CONFIG_LATENCYTOP is not set -# CONFIG_LBDAF is not set -# CONFIG_LBD is not set +CONFIG_LBDAF=y # CONFIG_LCD_LTV350QV is not set # CONFIG_LCD_TDO24M is not set # CONFIG_LCD_VGG2432A4 is not set @@ -1446,12 +1445,12 @@ CONFIG_NFSD_TCP=y # CONFIG_NFSD_V2_ACL is not set # CONFIG_NFSD_V3_ACL is not set CONFIG_NFSD_V3=y -CONFIG_NFSD_V4=y +# CONFIG_NFSD_V4 is not set # CONFIG_NFS_FS is not set # CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V3=y # CONFIG_NFS_V4_1 is not set -CONFIG_NFS_V4=y +# CONFIG_NFS_V4 is not set # CONFIG_NFTL is not set # CONFIG_NILFS2_FS is not set CONFIG_NL80211=y @@ -1766,6 +1765,7 @@ CONFIG_RTC_LIB=y # CONFIG_RTL8366_SMI is not set # CONFIG_RTL8366S_PHY_DEBUG_FS is not set # CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366RB_PHY is not set CONFIG_RT_MUTEXES=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_S2IO is not set diff --git a/target/linux/generic-2.6/config-2.6.32 b/target/linux/generic-2.6/config-2.6.32 index edd1394e4..b1f1f7fd1 100644 --- a/target/linux/generic-2.6/config-2.6.32 +++ b/target/linux/generic-2.6/config-2.6.32 @@ -491,6 +491,7 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_DL2K is not set # CONFIG_DLM is not set +# CONFIG_DMA_API_DEBUG is not set # CONFIG_DMADEVICES is not set # CONFIG_DMA_ENGINE is not set # CONFIG_DMASCC is not set @@ -607,6 +608,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_FB_SYS_IMAGEBLIT is not set # CONFIG_FB_TILEBLITTING is not set # CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set # CONFIG_FB_VGA16 is not set # CONFIG_FB_VIA is not set # CONFIG_FB_VIRTUAL is not set @@ -1107,8 +1109,7 @@ CONFIG_KMOD=y # CONFIG_LAPB is not set # CONFIG_LASAT is not set # CONFIG_LATENCYTOP is not set -# CONFIG_LBDAF is not set -# CONFIG_LBD is not set +CONFIG_LBDAF=y # CONFIG_LDM_PARTITION is not set # CONFIG_LEDS_ALIX is not set # CONFIG_LEDS_BD2802 is not set @@ -1314,6 +1315,7 @@ CONFIG_MTD_ROOTFS_SPLIT=y # CONFIG_MTD_TESTS is not set # CONFIG_MTD_UBI is not set CONFIG_MTD=y +# CONFIG_MV643XX_ETH is not set # CONFIG_MVSWITCH_PHY is not set # CONFIG_MWAVE is not set # CONFIG_MWL8K is not set @@ -1513,12 +1515,12 @@ CONFIG_NFSD_TCP=y # CONFIG_NFSD_V2_ACL is not set # CONFIG_NFSD_V3_ACL is not set CONFIG_NFSD_V3=y -CONFIG_NFSD_V4=y +# CONFIG_NFSD_V4 is not set # CONFIG_NFS_FS is not set # CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V3=y # CONFIG_NFS_V4_1 is not set -CONFIG_NFS_V4=y +# CONFIG_NFS_V4 is not set # CONFIG_NFTL is not set # CONFIG_NILFS2_FS is not set CONFIG_NL80211=y @@ -1652,7 +1654,9 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_PCI_ATMEL is not set # CONFIG_PCI_DEBUG is not set # CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCIEAER_INJECT is not set # CONFIG_PCIEASPM is not set +# CONFIG_PCIE_ECRC is not set # CONFIG_PCI_HERMES is not set # CONFIG_PCI_IOV is not set # CONFIG_PCI_LEGACY is not set @@ -1682,6 +1686,8 @@ CONFIG_PCI=y # CONFIG_PCSPKR_PLATFORM is not set # CONFIG_PD6729 is not set # CONFIG_PDC_ADMA is not set +# CONFIG_PERF_COUNTERS is not set +# CONFIG_PERF_EVENTS is not set # CONFIG_PHANTOM is not set # CONFIG_PHONE is not set # CONFIG_PHONET is not set @@ -1701,6 +1707,7 @@ CONFIG_PLIST=y CONFIG_PPC_4K_PAGES=y CONFIG_PPC4xx_GPIO=y # CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set # CONFIG_PPC_EMULATED_STATS is not set # CONFIG_PPP_ASYNC is not set # CONFIG_PPP_BSDCOMP is not set @@ -1847,6 +1854,7 @@ CONFIG_RTC_LIB=y # CONFIG_RTL8366_SMI is not set # CONFIG_RTL8366S_PHY_DEBUG_FS is not set # CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366RB_PHY is not set CONFIG_RT_MUTEXES=y # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_RUNTIME_DEBUG is not set @@ -2767,6 +2775,8 @@ CONFIG_XFRM=y # CONFIG_XFS_QUOTA is not set # CONFIG_XFS_RT is not set # CONFIG_XFS_SECURITY is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_LL_TEMAC is not set # CONFIG_XIP_KERNEL is not set # CONFIG_YAFFS_FS is not set # CONFIG_YAM is not set diff --git a/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h b/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h index b8a4f23d4..741dce917 100644 --- a/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h +++ b/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h @@ -62,16 +62,16 @@ #define AR8216_ATU_ACTIVE BIT(3) #define AR8216_ATU_PORT_NUM BITS(8, 4) #define AR8216_ATU_FULL_VIO BIT(12) -#define AR8216_ATU_ADDR4 BIT(16, 8) -#define AR8216_ATU_ADDR5 BIT(24, 8) +#define AR8216_ATU_ADDR4 BITS(16, 8) +#define AR8216_ATU_ADDR5 BITS(24, 8) #define AR8216_REG_ATU_DATA 0x0054 -#define AR8216_ATU_ADDR3 BIT(0, 8) -#define AR8216_ATU_ADDR2 BIT(8, 8) -#define AR8216_ATU_ADDR1 BIT(16, 8) -#define AR8216_ATU_ADDR0 BIT(24, 8) +#define AR8216_ATU_ADDR3 BITS(0, 8) +#define AR8216_ATU_ADDR2 BITS(8, 8) +#define AR8216_ATU_ADDR1 BITS(16, 8) +#define AR8216_ATU_ADDR0 BITS(24, 8) -#define AR8216_PORT_OFFSET(_i) (0x0100 * (i + 1)) +#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1)) #define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000) #define AR8216_PORT_STATUS_SPEED BIT(0) #define AR8216_PORT_STATUS_SPEED_ERR BIT(1) diff --git a/target/linux/generic-2.6/files/drivers/net/phy/rtl8366rb.c b/target/linux/generic-2.6/files/drivers/net/phy/rtl8366rb.c new file mode 100644 index 000000000..2739031e2 --- /dev/null +++ b/target/linux/generic-2.6/files/drivers/net/phy/rtl8366rb.c @@ -0,0 +1,1752 @@ +/* + * Platform driver for the Realtek RTL8366S ethernet switch + * + * Copyright (C) 2009-2010 Gabor Juhos + * Copyright (C) 2010 Antti Seppälä + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS +#include +#endif + +#define RTL8366S_DRIVER_DESC "Realtek RTL8366RB ethernet switch driver" +#define RTL8366S_DRIVER_VER "0.2.0" + +#define RTL8366S_PHY_NO_MAX 4 +#define RTL8366S_PHY_PAGE_MAX 7 +#define RTL8366S_PHY_ADDR_MAX 31 + +#define RTL8366_CHIP_GLOBAL_CTRL_REG 0x0000 +#define RTL8366_CHIP_CTRL_VLAN (1 << 13) +#define RTL8366_CHIP_CTRL_VLAN_4KTB (1 << 14) + +#define RTL8366_RESET_CTRL_REG 0x0100 +#define RTL8366_CHIP_CTRL_RESET_HW 1 +#define RTL8366_CHIP_CTRL_RESET_SW (1 << 1) + +#define RTL8366S_CHIP_VERSION_CTRL_REG 0x050A +#define RTL8366S_CHIP_VERSION_MASK 0xf +#define RTL8366S_CHIP_ID_REG 0x0509 +#define RTL8366S_CHIP_ID_8366 0x5937 + +/* PHY registers control */ +#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8000 +#define RTL8366S_PHY_ACCESS_DATA_REG 0x8002 + +#define RTL8366S_PHY_CTRL_READ 1 +#define RTL8366S_PHY_CTRL_WRITE 0 + +#define RTL8366S_PHY_REG_MASK 0x1f +#define RTL8366S_PHY_PAGE_OFFSET 5 +#define RTL8366S_PHY_PAGE_MASK (0xf << 5) +#define RTL8366S_PHY_NO_OFFSET 9 +#define RTL8366S_PHY_NO_MASK (0x1f << 9) + +/* LED control registers */ +#define RTL8366_LED_BLINKRATE_REG 0x0430 +#define RTL8366_LED_BLINKRATE_BIT 0 +#define RTL8366_LED_BLINKRATE_MASK 0x0007 + +#define RTL8366_LED_CTRL_REG 0x0431 +#define RTL8366_LED_0_1_CTRL_REG 0x0432 +#define RTL8366_LED_2_3_CTRL_REG 0x0433 + +#define RTL8366S_MIB_COUNT 33 +#define RTL8366S_GLOBAL_MIB_COUNT 1 +#define RTL8366S_MIB_COUNTER_PORT_OFFSET 0x0050 +#define RTL8366S_MIB_COUNTER_BASE 0x1000 +#define RTL8366S_MIB_CTRL_REG 0x13F0 +#define RTL8366S_MIB_CTRL_USER_MASK 0x0FFC +#define RTL8366S_MIB_CTRL_BUSY_MASK 0x0001 +#define RTL8366S_MIB_CTRL_RESET_MASK 0x0001 + +#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK 0x0004 +#define RTL8366S_MIB_CTRL_PORT_RESET_BIT 0x0003 +#define RTL8366S_MIB_CTRL_PORT_RESET_MASK 0x01FC + + +#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0063 +#define RTL8366S_PORT_VLAN_CTRL_REG(_p) \ + (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4) +#define RTL8366S_PORT_VLAN_CTRL_MASK 0xf +#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) + + +#define RTL8366S_VLAN_TABLE_READ_BASE 0x018C +#define RTL8366S_VLAN_TABLE_WRITE_BASE 0x0185 + + +#define RTL8366S_TABLE_ACCESS_CTRL_REG 0x0180 +#define RTL8366S_TABLE_VLAN_READ_CTRL 0x0E01 +#define RTL8366S_TABLE_VLAN_WRITE_CTRL 0x0F01 + +#define RTL8366S_VLAN_MEMCONF_BASE 0x0020 + + +#define RTL8366S_PORT_LINK_STATUS_BASE 0x0014 +#define RTL8366S_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8366S_PORT_STATUS_DUPLEX_MASK 0x0004 +#define RTL8366S_PORT_STATUS_LINK_MASK 0x0010 +#define RTL8366S_PORT_STATUS_TXPAUSE_MASK 0x0020 +#define RTL8366S_PORT_STATUS_RXPAUSE_MASK 0x0040 +#define RTL8366S_PORT_STATUS_AN_MASK 0x0080 + + +#define RTL8366_PORT_NUM_CPU 5 +#define RTL8366_NUM_PORTS 6 +#define RTL8366_NUM_VLANS 16 +#define RTL8366_NUM_LEDGROUPS 4 +#define RTL8366_NUM_VIDS 4096 +#define RTL8366S_PRIORITYMAX 7 +#define RTL8366S_FIDMAX 7 + + +#define RTL8366_PORT_1 (1 << 0) /* In userspace port 0 */ +#define RTL8366_PORT_2 (1 << 1) /* In userspace port 1 */ +#define RTL8366_PORT_3 (1 << 2) /* In userspace port 2 */ +#define RTL8366_PORT_4 (1 << 3) /* In userspace port 3 */ +#define RTL8366_PORT_5 (1 << 4) /* In userspace port 4 */ + +#define RTL8366_PORT_CPU (1 << 5) /* CPU port */ + +#define RTL8366_PORT_ALL (RTL8366_PORT_1 | \ + RTL8366_PORT_2 | \ + RTL8366_PORT_3 | \ + RTL8366_PORT_4 | \ + RTL8366_PORT_5 | \ + RTL8366_PORT_CPU) + +#define RTL8366_PORT_ALL_BUT_CPU (RTL8366_PORT_1 | \ + RTL8366_PORT_2 | \ + RTL8366_PORT_3 | \ + RTL8366_PORT_4 | \ + RTL8366_PORT_5) + +#define RTL8366_PORT_ALL_EXTERNAL (RTL8366_PORT_1 | \ + RTL8366_PORT_2 | \ + RTL8366_PORT_3 | \ + RTL8366_PORT_4) + +#define RTL8366_PORT_ALL_INTERNAL RTL8366_PORT_CPU + +struct rtl8366rb { + struct device *parent; + struct rtl8366_smi smi; + struct mii_bus *mii_bus; + int mii_irq[PHY_MAX_ADDR]; + struct switch_dev dev; + char buf[4096]; +#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS + struct dentry *debugfs_root; +#endif +}; + +struct rtl8366rb_vlanconfig { + u16 reserved2:1; + u16 priority:3; + u16 vid:12; + u16 untag:8; + u16 member:8; + u16 stag_mbr:8; + u16 stag_idx:3; + u16 reserved1:2; + u16 fid:3; +}; + +struct rtl8366rb_vlan4kentry { + u16 reserved1:4; + u16 vid:12; + u16 untag:8; + u16 member:8; + u16 reserved2:13; + u16 fid:3; +}; + + +#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS +u16 gl_dbg_reg; +#endif + +struct mib_counter { + unsigned offset; + unsigned length; + const char *name; +}; + +static struct mib_counter rtl8366rb_mib_counters[RTL8366S_MIB_COUNT] = { + { 0, 4, "IfInOctets " }, + { 4, 4, "EtherStatsOctets " }, + { 8, 2, "EtherStatsUnderSizePkts " }, + { 10, 2, "EtherFregament " }, + { 12, 2, "EtherStatsPkts64Octets " }, + { 14, 2, "EtherStatsPkts65to127Octets " }, + { 16, 2, "EtherStatsPkts128to255Octets " }, + { 18, 2, "EtherStatsPkts256to511Octets " }, + { 20, 2, "EtherStatsPkts512to1023Octets " }, + { 22, 2, "EtherStatsPkts1024to1518Octets " }, + { 24, 2, "EtherOversizeStats " }, + { 26, 2, "EtherStatsJabbers " }, + { 28, 2, "IfInUcastPkts " }, + { 30, 2, "EtherStatsMulticastPkts " }, + { 32, 2, "EtherStatsBroadcastPkts " }, + { 34, 2, "EtherStatsDropEvents " }, + { 36, 2, "Dot3StatsFCSErrors " }, + { 38, 2, "Dot3StatsSymbolErrors " }, + { 40, 2, "Dot3InPauseFrames " }, + { 42, 2, "Dot3ControlInUnknownOpcodes " }, + { 44, 2, "IfOutOctets " }, + { 46, 2, "Dot3StatsSingleCollisionFrames " }, + { 48, 2, "Dot3StatMultipleCollisionFrames " }, + { 50, 2, "Dot3sDeferredTransmissions " }, + { 52, 2, "Dot3StatsLateCollisions " }, + { 54, 2, "EtherStatsCollisions " }, + { 56, 2, "Dot3StatsExcessiveCollisions " }, + { 58, 2, "Dot3OutPauseFrames " }, + { 60, 2, "Dot1dBasePortDelayExceededDiscards" }, + { 62, 2, "Dot1dTpPortInDiscards " }, + { 64, 2, "IfOutUcastPkts " }, + { 66, 2, "IfOutMulticastPkts " }, + { 68, 2, "IfOutBroadcastPkts " }, +}; + +static inline struct rtl8366rb *sw_to_rtl8366rb(struct switch_dev *sw) +{ + return container_of(sw, struct rtl8366rb, dev); +} + +static int rtl8366rb_reset_chip(struct rtl8366rb *rtl) +{ + struct rtl8366_smi *smi = &rtl->smi; + int timeout = 10; + u32 data; + + rtl8366_smi_write_reg(smi, RTL8366_RESET_CTRL_REG, + RTL8366_CHIP_CTRL_RESET_HW); + do { + msleep(1); + if (rtl8366_smi_read_reg(smi, RTL8366_RESET_CTRL_REG, &data)) + return -EIO; + + if (!(data & RTL8366_CHIP_CTRL_RESET_HW)) + break; + } while (--timeout); + + if (!timeout) { + printk("Timeout waiting for the switch to reset\n"); + return -EIO; + } + + return 0; +} + +static int rtl8366rb_read_phy_reg(struct rtl8366rb *rtl, + u32 phy_no, u32 page, u32 addr, u32 *data) +{ + struct rtl8366_smi *smi = &rtl->smi; + u32 reg; + int ret; + + if (phy_no > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366S_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366S_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_READ); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | + ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | + (addr & RTL8366S_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, 0); + if (ret) + return ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366S_PHY_ACCESS_DATA_REG, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366rb_write_phy_reg(struct rtl8366rb *rtl, + u32 phy_no, u32 page, u32 addr, u32 data) +{ + struct rtl8366_smi *smi = &rtl->smi; + u32 reg; + int ret; + + if (phy_no > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366S_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366S_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_WRITE); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | + ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | + (addr & RTL8366S_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366_get_mib_counter(struct rtl8366rb *rtl, int counter, + int port, unsigned long long *val) +{ + struct rtl8366_smi *smi = &rtl->smi; + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8366_NUM_PORTS || counter >= RTL8366S_MIB_COUNT) + return -EINVAL; + + addr = RTL8366S_MIB_COUNTER_BASE + + RTL8366S_MIB_COUNTER_PORT_OFFSET * (port) + + rtl8366rb_mib_counters[counter].offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + data = 0; /* writing data will be discard by ASIC */ + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + + /* read MIB control register */ + err = rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data); + if (err) + return err; + + if (data & RTL8366S_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8366S_MIB_CTRL_RESET_MASK) + return -EIO; + + mibvalue = 0; + for (i = rtl8366rb_mib_counters[counter].length; i > 0; i--) { + err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); + if (err) + return err; + + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8366rb_get_vlan_4k_entry(struct rtl8366rb *rtl, u32 vid, + struct rtl8366rb_vlan4kentry *vlan4k) +{ + struct rtl8366_smi *smi = &rtl->smi; + int err; + u32 data; + u16 *tableaddr; + + memset(vlan4k, '\0', sizeof(struct rtl8366rb_vlan4kentry)); + vlan4k->vid = vid; + + if (vid >= RTL8366_NUM_VIDS) + return -EINVAL; + + tableaddr = (u16 *)vlan4k; + + /* write VID */ + data = *tableaddr; + err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, data); + if (err) + return err; + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_READ_CTRL); + if (err) + return err; + + err = rtl8366_smi_read_reg(smi, RTL8366S_VLAN_TABLE_READ_BASE, &data); + if (err) + return err; + + *tableaddr = data; + tableaddr++; + + err = rtl8366_smi_read_reg(smi, RTL8366S_VLAN_TABLE_READ_BASE + 1, + &data); + if (err) + return err; + + *tableaddr = data; + tableaddr++; + + err = rtl8366_smi_read_reg(smi, RTL8366S_VLAN_TABLE_READ_BASE + 2, + &data); + if (err) + return err; + *tableaddr = data; + vlan4k->vid = vid; + + return 0; +} + +static int rtl8366rb_set_vlan_4k_entry(struct rtl8366rb *rtl, + const struct rtl8366rb_vlan4kentry *vlan4k) +{ + struct rtl8366_smi *smi = &rtl->smi; + int err; + u32 data; + u16 *tableaddr; + + if (vlan4k->vid >= RTL8366_NUM_VIDS || + vlan4k->member > RTL8366_PORT_ALL || + vlan4k->untag > RTL8366_PORT_ALL || + vlan4k->fid > RTL8366S_FIDMAX) + return -EINVAL; + + tableaddr = (u16 *)vlan4k; + + data = *tableaddr; + + err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, data); + if (err) + return err; + + tableaddr++; + + data = *tableaddr; + + err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE + 1, + data); + if (err) + return err; + + tableaddr++; + + data = *tableaddr; + + err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE + 2, + data); + if (err) + return err; + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_WRITE_CTRL); + + return err; +} + +static int rtl8366rb_get_vlan_member_config(struct rtl8366rb *rtl, u32 index, + struct rtl8366rb_vlanconfig *vlanmc) +{ + struct rtl8366_smi *smi = &rtl->smi; + int err; + u32 addr; + u32 data; + u16 *tableaddr; + + memset(vlanmc, '\0', sizeof(struct rtl8366rb_vlanconfig)); + + if (index >= RTL8366_NUM_VLANS) + return -EINVAL; + + tableaddr = (u16 *)vlanmc; + + addr = RTL8366S_VLAN_MEMCONF_BASE + (index * 3); + err = rtl8366_smi_read_reg(smi, addr, &data); + if (err) + return err; + + *tableaddr = data; + tableaddr++; + + addr = RTL8366S_VLAN_MEMCONF_BASE + 1 + (index * 3); + err = rtl8366_smi_read_reg(smi, addr, &data); + if (err) + return err; + + *tableaddr = data; + tableaddr++; + + addr = RTL8366S_VLAN_MEMCONF_BASE + 2 + (index * 3); + err = rtl8366_smi_read_reg(smi, addr, &data); + if (err) + return err; + + *tableaddr = data; + + return 0; +} + +static int rtl8366rb_set_vlan_member_config(struct rtl8366rb *rtl, u32 index, + const struct rtl8366rb_vlanconfig + *vlanmc) +{ + struct rtl8366_smi *smi = &rtl->smi; + int err; + u32 addr; + u32 data; + u16 *tableaddr; + + if (index >= RTL8366_NUM_VLANS || + vlanmc->vid >= RTL8366_NUM_VIDS || + vlanmc->priority > RTL8366S_PRIORITYMAX || + vlanmc->member > RTL8366_PORT_ALL || + vlanmc->untag > RTL8366_PORT_ALL || + vlanmc->fid > RTL8366S_FIDMAX) + return -EINVAL; + + addr = RTL8366S_VLAN_MEMCONF_BASE + (index * 3); + + tableaddr = (u16 *)vlanmc; + data = *tableaddr; + + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + + addr = RTL8366S_VLAN_MEMCONF_BASE + 1 + (index * 3); + + tableaddr++; + data = *tableaddr; + + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + + addr = RTL8366S_VLAN_MEMCONF_BASE + 2 + (index * 3); + + tableaddr++; + data = *tableaddr; + + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + return 0; +} + +static int rtl8366rb_get_port_vlan_index(struct rtl8366rb *rtl, int port, + int *val) +{ + struct rtl8366_smi *smi = &rtl->smi; + u32 data; + int err; + + if (port >= RTL8366_NUM_PORTS) + return -EINVAL; + + err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), + &data); + if (err) + return err; + + *val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) & + RTL8366S_PORT_VLAN_CTRL_MASK; + + return 0; + +} + +static int rtl8366rb_get_vlan_port_pvid(struct rtl8366rb *rtl, int port, + int *val) +{ + struct rtl8366rb_vlanconfig vlanmc; + int err; + int index; + + err = rtl8366rb_get_port_vlan_index(rtl, port, &index); + if (err) + return err; + + err = rtl8366rb_get_vlan_member_config(rtl, index, &vlanmc); + if (err) + return err; + + *val = vlanmc.vid; + return 0; +} + +static int rtl8366rb_set_port_vlan_index(struct rtl8366rb *rtl, int port, + int index) +{ + struct rtl8366_smi *smi = &rtl->smi; + u32 data; + int err; + + if (port >= RTL8366_NUM_PORTS || index >= RTL8366_NUM_VLANS) + return -EINVAL; + + err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), + &data); + if (err) + return err; + + data &= ~(RTL8366S_PORT_VLAN_CTRL_MASK << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port)); + data |= (index & RTL8366S_PORT_VLAN_CTRL_MASK) << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port); + + err = rtl8366_smi_write_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), + data); + return err; +} + +static int rtl8366rb_set_vlan_port_pvid(struct rtl8366rb *rtl, int port, int val) +{ + int i; + struct rtl8366rb_vlanconfig vlanmc; + struct rtl8366rb_vlan4kentry vlan4k; + + if (port >= RTL8366_NUM_PORTS || val >= RTL8366_NUM_VIDS) + return -EINVAL; + + /* Updating the 4K entry; lookup it and change the port member set */ + rtl8366rb_get_vlan_4k_entry(rtl, val, &vlan4k); + vlan4k.member |= ((1 << port) | RTL8366_PORT_CPU); + vlan4k.untag = RTL8366_PORT_ALL_BUT_CPU; + rtl8366rb_set_vlan_4k_entry(rtl, &vlan4k); + + /* + * For the 16 entries more work needs to be done. First see if such + * VID is already there and change it + */ + for (i = 0; i < RTL8366_NUM_VLANS; ++i) { + rtl8366rb_get_vlan_member_config(rtl, i, &vlanmc); + + /* Try to find an existing vid and update port member set */ + if (val == vlanmc.vid) { + vlanmc.member |= ((1 << port) | RTL8366_PORT_CPU); + rtl8366rb_set_vlan_member_config(rtl, i, &vlanmc); + + /* Now update PVID register settings */ + rtl8366rb_set_port_vlan_index(rtl, port, i); + + return 0; + } + } + + /* + * PVID could not be found from vlan table. Replace unused (one that + * has no member ports) with new one + */ + for (i = 0; i < RTL8366_NUM_VLANS; ++i) { + rtl8366rb_get_vlan_member_config(rtl, i, &vlanmc); + + /* + * See if this vlan member configuration is unused. It is + * unused if member set contains no ports or CPU port only + */ + if (!vlanmc.member || vlanmc.member == RTL8366_PORT_CPU) { + vlanmc.vid = val; + vlanmc.priority = 0; + vlanmc.untag = RTL8366_PORT_ALL_BUT_CPU; + vlanmc.member = ((1 << port) | RTL8366_PORT_CPU); + vlanmc.fid = 0; + + rtl8366rb_set_vlan_member_config(rtl, i, &vlanmc); + + /* Now update PVID register settings */ + rtl8366rb_set_port_vlan_index(rtl, port, i); + + return 0; + } + } + + dev_err(rtl->parent, + "All 16 vlan member configurations are in use\n"); + + return -EINVAL; +} + + +static int rtl8366rb_vlan_set_vlan(struct rtl8366rb *rtl, int enable) +{ + struct rtl8366_smi *smi = &rtl->smi; + u32 data = 0; + + rtl8366_smi_read_reg(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, &data); + + if (enable) + data |= RTL8366_CHIP_CTRL_VLAN; + else + data &= ~RTL8366_CHIP_CTRL_VLAN; + + return rtl8366_smi_write_reg(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, data); +} + +static int rtl8366rb_vlan_set_4ktable(struct rtl8366rb *rtl, int enable) +{ + struct rtl8366_smi *smi = &rtl->smi; + u32 data = 0; + + rtl8366_smi_read_reg(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, &data); + + if (enable) + data |= RTL8366_CHIP_CTRL_VLAN_4KTB; + else + data &= ~RTL8366_CHIP_CTRL_VLAN_4KTB; + + return rtl8366_smi_write_reg(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, data); +} + +static int rtl8366rb_reset_vlan(struct rtl8366rb *rtl) +{ + struct rtl8366rb_vlan4kentry vlan4k; + struct rtl8366rb_vlanconfig vlanmc; + int err; + int i; + + /* clear 16 VLAN member configuration */ + vlanmc.vid = 0; + vlanmc.priority = 0; + vlanmc.member = 0; + vlanmc.untag = 0; + vlanmc.fid = 0; + for (i = 0; i < RTL8366_NUM_VLANS; i++) { + err = rtl8366rb_set_vlan_member_config(rtl, i, &vlanmc); + if (err) + return err; + } + + /* Set a default VLAN with vid 1 to 4K table for all ports */ + vlan4k.vid = 1; + vlan4k.member = RTL8366_PORT_ALL; + vlan4k.untag = RTL8366_PORT_ALL; + vlan4k.fid = 0; + err = rtl8366rb_set_vlan_4k_entry(rtl, &vlan4k); + if (err) + return err; + + /* Set all ports PVID to default VLAN */ + for (i = 0; i < RTL8366_NUM_PORTS; i++) { + err = rtl8366rb_set_vlan_port_pvid(rtl, i, 0); + if (err) + return err; + } + + return 0; +} + +#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS +static int rtl8366rb_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t rtl8366rb_read_debugfs_mibs(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366rb *rtl = (struct rtl8366rb *)file->private_data; + int i, j, len = 0; + char *buf = rtl->buf; + + len += snprintf(buf + len, sizeof(rtl->buf) - len, "MIB Counters:\n"); + len += snprintf(buf + len, sizeof(rtl->buf) - len, "Counter" + " " + "Port 0 \t\t Port 1 \t\t Port 2 \t\t Port 3 \t\t " + "Port 4\n"); + + for (i = 0; i < 33; ++i) { + len += snprintf(buf + len, sizeof(rtl->buf) - len, "%d:%s ", + i, rtl8366rb_mib_counters[i].name); + for (j = 0; j < RTL8366_NUM_PORTS; ++j) { + unsigned long long counter = 0; + + if (!rtl8366_get_mib_counter(rtl, i, j, &counter)) + len += snprintf(buf + len, + sizeof(rtl->buf) - len, + "[%llu]", counter); + else + len += snprintf(buf + len, + sizeof(rtl->buf) - len, + "[error]"); + + if (j != RTL8366_NUM_PORTS - 1) { + if (counter < 100000) + len += snprintf(buf + len, + sizeof(rtl->buf) - len, + "\t"); + + len += snprintf(buf + len, + sizeof(rtl->buf) - len, + "\t"); + } + } + len += snprintf(buf + len, sizeof(rtl->buf) - len, "\n"); + } + + len += snprintf(buf + len, sizeof(rtl->buf) - len, "\n"); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366rb_read_debugfs_vlan(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366rb *rtl = (struct rtl8366rb *)file->private_data; + int i, j, len = 0; + char *buf = rtl->buf; + + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "VLAN Member Config:\n"); + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "\t id \t vid \t prio \t member \t untag \t fid " + "\tports\n"); + + for (i = 0; i < RTL8366_NUM_VLANS; ++i) { + struct rtl8366rb_vlanconfig vlanmc; + + rtl8366rb_get_vlan_member_config(rtl, i, &vlanmc); + + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "\t[%d] \t %d \t %d \t 0x%04x \t 0x%04x \t %d " + "\t", i, vlanmc.vid, vlanmc.priority, + vlanmc.member, vlanmc.untag, vlanmc.fid); + + for (j = 0; j < RTL8366_NUM_PORTS; ++j) { + int index = 0; + if (!rtl8366rb_get_port_vlan_index(rtl, j, &index)) { + if (index == i) + len += snprintf(buf + len, + sizeof(rtl->buf) - len, + "%d", j); + } + } + len += snprintf(buf + len, sizeof(rtl->buf) - len, "\n"); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366rb_read_debugfs_reg(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366rb *rtl = (struct rtl8366rb *)file->private_data; + struct rtl8366_smi *smi = &rtl->smi; + u32 t, reg = gl_dbg_reg; + int err, len = 0; + char *buf = rtl->buf; + + memset(buf, '\0', sizeof(rtl->buf)); + + err = rtl8366_smi_read_reg(smi, reg, &t); + if (err) { + len += snprintf(buf, sizeof(rtl->buf), + "Read failed (reg: 0x%04x)\n", reg); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + } + + len += snprintf(buf, sizeof(rtl->buf), "reg = 0x%04x, val = 0x%04x\n", + reg, t); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366rb_write_debugfs_reg(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366rb *rtl = (struct rtl8366rb *)file->private_data; + struct rtl8366_smi *smi = &rtl->smi; + unsigned long data; + u32 reg = gl_dbg_reg; + int err; + size_t len; + char *buf = rtl->buf; + + len = min(count, sizeof(rtl->buf) - 1); + if (copy_from_user(buf, user_buf, len)) { + dev_err(rtl->parent, "copy from user failed\n"); + return -EFAULT; + } + + buf[len] = '\0'; + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + + if (strict_strtoul(buf, 16, &data)) { + dev_err(rtl->parent, "Invalid reg value %s\n", buf); + } else { + err = rtl8366_smi_write_reg(smi, reg, data); + if (err) { + dev_err(rtl->parent, + "writing reg 0x%04x val 0x%04lx failed\n", + reg, data); + } + } + + return count; +} + +static const struct file_operations fops_rtl8366rb_regs = { + .read = rtl8366rb_read_debugfs_reg, + .write = rtl8366rb_write_debugfs_reg, + .open = rtl8366rb_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366rb_vlan = { + .read = rtl8366rb_read_debugfs_vlan, + .open = rtl8366rb_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366rb_mibs = { + .read = rtl8366rb_read_debugfs_mibs, + .open = rtl8366rb_debugfs_open, + .owner = THIS_MODULE +}; + +static void rtl8366rb_debugfs_init(struct rtl8366rb *rtl) +{ + struct dentry *node; + struct dentry *root; + + if (!rtl->debugfs_root) + rtl->debugfs_root = debugfs_create_dir("rtl8366rb", NULL); + + if (!rtl->debugfs_root) { + dev_err(rtl->parent, "Unable to create debugfs dir\n"); + return; + } + root = rtl->debugfs_root; + + node = debugfs_create_x16("reg", S_IRUGO | S_IWUSR, root, &gl_dbg_reg); + if (!node) { + dev_err(rtl->parent, "Creating debugfs file reg failed\n"); + return; + } + + node = debugfs_create_file("val", S_IRUGO | S_IWUSR, root, rtl, + &fops_rtl8366rb_regs); + if (!node) { + dev_err(rtl->parent, "Creating debugfs file val failed\n"); + return; + } + + node = debugfs_create_file("vlan", S_IRUSR, root, rtl, + &fops_rtl8366rb_vlan); + if (!node) { + dev_err(rtl->parent, + "Creating debugfs file vlan failed\n"); + return; + } + + node = debugfs_create_file("mibs", S_IRUSR, root, rtl, + &fops_rtl8366rb_mibs); + if (!node) { + dev_err(rtl->parent, + "Creating debugfs file mibs failed\n"); + return; + } +} + +static void rtl8366rb_debugfs_remove(struct rtl8366rb *rtl) +{ + if (rtl->debugfs_root) { + debugfs_remove_recursive(rtl->debugfs_root); + rtl->debugfs_root = NULL; + } +} + +#else +static inline void rtl8366rb_debugfs_init(struct rtl8366rb *rtl) {} +static inline void rtl8366rb_debugfs_remove(struct rtl8366rb *rtl) {} +#endif /* CONFIG_RTL8366S_PHY_DEBUG_FS */ + +static int rtl8366rb_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct rtl8366_smi *smi = &rtl->smi; + u32 data = 0; + + if (val->value.i == 1) { + rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data); + data |= (1 << 2); + rtl8366_smi_write_reg(smi, RTL8366S_MIB_CTRL_REG, data); + } + + return 0; +} + +static int rtl8366rb_sw_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct rtl8366_smi *smi = &rtl->smi; + u32 data; + + if (attr->ofs == 1) { + rtl8366_smi_read_reg(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, &data); + + if (data & RTL8366_CHIP_CTRL_VLAN) + val->value.i = 1; + else + val->value.i = 0; + } else if (attr->ofs == 2) { + rtl8366_smi_read_reg(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, &data); + + if (data & RTL8366_CHIP_CTRL_VLAN_4KTB) + val->value.i = 1; + else + val->value.i = 0; + } + + return 0; +} + +static int rtl8366rb_sw_get_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct rtl8366_smi *smi = &rtl->smi; + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366_LED_BLINKRATE_REG, &data); + + val->value.i = (data & (RTL8366_LED_BLINKRATE_MASK)); + + return 0; +} + +static int rtl8366rb_sw_set_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct rtl8366_smi *smi = &rtl->smi; + u32 data; + + if (val->value.i >= 6) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366_LED_BLINKRATE_REG, &data); + + data &= ~RTL8366_LED_BLINKRATE_MASK; + data |= val->value.i; + + rtl8366_smi_write_reg(smi, RTL8366_LED_BLINKRATE_REG, data); + + return 0; +} + +static int rtl8366rb_sw_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + + if (attr->ofs == 1) + return rtl8366rb_vlan_set_vlan(rtl, val->value.i); + else + return rtl8366rb_vlan_set_4ktable(rtl, val->value.i); +} + +static const char *rtl8366rb_speed_str(unsigned speed) +{ + switch (speed) { + case 0: + return "10baseT"; + case 1: + return "100baseT"; + case 2: + return "1000baseT"; + } + + return "unknown"; +} + +static int rtl8366rb_sw_get_port_link(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct rtl8366_smi *smi = &rtl->smi; + u32 len = 0, data = 0; + + if (val->port_vlan >= RTL8366_NUM_PORTS) + return -EINVAL; + + memset(rtl->buf, '\0', sizeof(rtl->buf)); + rtl8366_smi_read_reg(smi, RTL8366S_PORT_LINK_STATUS_BASE + + (val->port_vlan / 2), &data); + + if (val->port_vlan % 2) + data = data >> 8; + + len = snprintf(rtl->buf, sizeof(rtl->buf), + "port:%d link:%s speed:%s %s-duplex %s%s%s", + val->port_vlan, + (data & RTL8366S_PORT_STATUS_LINK_MASK) ? "up" : "down", + rtl8366rb_speed_str(data & + RTL8366S_PORT_STATUS_SPEED_MASK), + (data & RTL8366S_PORT_STATUS_DUPLEX_MASK) ? + "full" : "half", + (data & RTL8366S_PORT_STATUS_TXPAUSE_MASK) ? + "tx-pause ": "", + (data & RTL8366S_PORT_STATUS_RXPAUSE_MASK) ? + "rx-pause " : "", + (data & RTL8366S_PORT_STATUS_AN_MASK) ? "nway ": ""); + + val->value.s = rtl->buf; + val->len = len; + + return 0; +} + +static int rtl8366rb_sw_get_vlan_info(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int i; + u32 len = 0; + struct rtl8366rb_vlanconfig vlanmc; + struct rtl8366rb_vlan4kentry vlan4k; + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + char *buf = rtl->buf; + + if (val->port_vlan >= RTL8366_NUM_VLANS) + return -EINVAL; + + memset(buf, '\0', sizeof(rtl->buf)); + + rtl8366rb_get_vlan_member_config(rtl, val->port_vlan, &vlanmc); + rtl8366rb_get_vlan_4k_entry(rtl, vlanmc.vid, &vlan4k); + + len += snprintf(buf + len, sizeof(rtl->buf) - len, "VLAN %d: Ports: ", + val->port_vlan); + + for (i = 0; i < RTL8366_NUM_PORTS; ++i) { + int index = 0; + if (!rtl8366rb_get_port_vlan_index(rtl, i, &index) && + index == val->port_vlan) + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "%d", i); + } + len += snprintf(buf + len, sizeof(rtl->buf) - len, "\n"); + + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "\t\t vid \t prio \t member \t untag \t fid\n"); + len += snprintf(buf + len, sizeof(rtl->buf) - len, "\tMC:\t"); + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "%d \t %d \t 0x%04x \t 0x%04x \t %d\n", + vlanmc.vid, vlanmc.priority, vlanmc.member, + vlanmc.untag, vlanmc.fid); + len += snprintf(buf + len, sizeof(rtl->buf) - len, "\t4K:\t"); + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "%d \t \t 0x%04x \t 0x%04x \t %d", + vlan4k.vid, vlan4k.member, vlan4k.untag, vlan4k.fid); + + val->value.s = buf; + val->len = len; + + return 0; +} + +static int rtl8366rb_sw_set_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct rtl8366_smi *smi = &rtl->smi; + u32 data = 0; + + if (val->port_vlan >= RTL8366_NUM_PORTS) + return -EINVAL; + + if (val->port_vlan == RTL8366_PORT_NUM_CPU) { + rtl8366_smi_read_reg(smi, RTL8366_LED_BLINKRATE_REG, &data); + data = (data & (~(0xF << 4))) | (val->value.i << 4); + rtl8366_smi_write_reg(smi, RTL8366_LED_BLINKRATE_REG, data); + } else { + rtl8366_smi_read_reg(smi, RTL8366_LED_CTRL_REG, &data); + data = (data & (~(0xF << (val->port_vlan * 4)))) | + (val->value.i << (val->port_vlan * 4)); + rtl8366_smi_write_reg(smi, RTL8366_LED_CTRL_REG, data); + } + + return 0; +} + +static int rtl8366rb_sw_get_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct rtl8366_smi *smi = &rtl->smi; + u32 data = 0; + + if (val->port_vlan >= RTL8366_NUM_LEDGROUPS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366_LED_CTRL_REG, &data); + val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; + + return 0; +} + +static int rtl8366rb_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct rtl8366_smi *smi = &rtl->smi; + u32 data = 0; + + if (val->port_vlan >= RTL8366_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data); + data |= (1 << (val->port_vlan + 3)); + rtl8366_smi_write_reg(smi, RTL8366S_MIB_CTRL_REG, data); + + return 0; +} + +static int rtl8366rb_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + int i, len = 0; + unsigned long long counter = 0; + char *buf = rtl->buf; + + if (val->port_vlan >= RTL8366_NUM_PORTS) + return -EINVAL; + + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "Port %d MIB counters\n", + val->port_vlan); + + for (i = 0; i < RTL8366S_MIB_COUNT; ++i) { + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "%d:%s\t", i, rtl8366rb_mib_counters[i].name); + if (!rtl8366_get_mib_counter(rtl, i, val->port_vlan, &counter)) + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "[%llu]\n", counter); + else + len += snprintf(buf + len, sizeof(rtl->buf) - len, + "[error]\n"); + } + + val->value.s = buf; + val->len = len; + return 0; +} + +static int rtl8366rb_sw_get_vlan_ports(struct switch_dev *dev, + struct switch_val *val) +{ + struct rtl8366rb_vlanconfig vlanmc; + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct switch_port *port; + int i; + + if (val->port_vlan >= RTL8366_NUM_VLANS) + return -EINVAL; + + rtl8366rb_get_vlan_member_config(rtl, val->port_vlan, &vlanmc); + + port = &val->value.ports[0]; + val->len = 0; + for (i = 0; i < RTL8366_NUM_PORTS; i++) { + if (!(vlanmc.member & BIT(i))) + continue; + + port->id = i; + port->flags = (vlanmc.untag & BIT(i)) ? + 0 : BIT(SWITCH_PORT_FLAG_TAGGED); + val->len++; + port++; + } + return 0; +} + +static int rtl8366rb_sw_set_vlan_ports(struct switch_dev *dev, + struct switch_val *val) +{ + struct rtl8366rb_vlanconfig vlanmc; + struct rtl8366rb_vlan4kentry vlan4k; + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + struct switch_port *port; + int i; + + if (val->port_vlan >= RTL8366_NUM_VLANS) + return -EINVAL; + + rtl8366rb_get_vlan_member_config(rtl, val->port_vlan, &vlanmc); + rtl8366rb_get_vlan_4k_entry(rtl, vlanmc.vid, &vlan4k); + + vlanmc.untag = 0; + vlanmc.member = 0; + + port = &val->value.ports[0]; + for (i = 0; i < val->len; i++, port++) { + vlanmc.member |= BIT(port->id); + + if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) + vlanmc.untag |= BIT(port->id); + } + + vlan4k.member = vlanmc.member; + vlan4k.untag = vlanmc.untag; + + rtl8366rb_set_vlan_member_config(rtl, val->port_vlan, &vlanmc); + rtl8366rb_set_vlan_4k_entry(rtl, &vlan4k); + return 0; +} + +static int rtl8366rb_sw_get_port_pvid(struct switch_dev *dev, int port, int *val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + return rtl8366rb_get_vlan_port_pvid(rtl, port, val); +} + +static int rtl8366rb_sw_set_port_pvid(struct switch_dev *dev, int port, int val) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + return rtl8366rb_set_vlan_port_pvid(rtl, port, val); +} + +static int rtl8366rb_sw_reset_switch(struct switch_dev *dev) +{ + struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); + int err; + + err = rtl8366rb_reset_chip(rtl); + if (err) + return err; + + return rtl8366rb_reset_vlan(rtl); +} + +static struct switch_attr rtl8366rb_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366rb_sw_set_vlan_enable, + .get = rtl8366rb_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366rb_sw_set_vlan_enable, + .get = rtl8366rb_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_INT, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8366rb_sw_reset_mibs, + .get = NULL, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "blinkrate", + .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," + " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", + .set = rtl8366rb_sw_set_blinkrate, + .get = rtl8366rb_sw_get_blinkrate, + .max = 5 + }, +}; + +static struct switch_attr rtl8366rb_port[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "link", + .description = "Get port link information", + .max = 1, + .set = NULL, + .get = rtl8366rb_sw_get_port_link, + }, { + .type = SWITCH_TYPE_INT, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .max = 1, + .set = rtl8366rb_sw_reset_port_mibs, + .get = NULL, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366rb_sw_get_port_mib, + }, { + .type = SWITCH_TYPE_INT, + .name = "led", + .description = "Get/Set port group (0 - 3) led mode (0 - 15)", + .max = 15, + .set = rtl8366rb_sw_set_port_led, + .get = rtl8366rb_sw_get_port_led, + }, +}; + +static struct switch_attr rtl8366rb_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366rb_sw_get_vlan_info, + }, +}; + +/* template */ +static struct switch_dev rtl8366_switch_dev = { + .name = "RTL8366S", + .cpu_port = RTL8366_PORT_NUM_CPU, + .ports = RTL8366_NUM_PORTS, + .vlans = RTL8366_NUM_VLANS, + .attr_global = { + .attr = rtl8366rb_globals, + .n_attr = ARRAY_SIZE(rtl8366rb_globals), + }, + .attr_port = { + .attr = rtl8366rb_port, + .n_attr = ARRAY_SIZE(rtl8366rb_port), + }, + .attr_vlan = { + .attr = rtl8366rb_vlan, + .n_attr = ARRAY_SIZE(rtl8366rb_vlan), + }, + + .get_vlan_ports = rtl8366rb_sw_get_vlan_ports, + .set_vlan_ports = rtl8366rb_sw_set_vlan_ports, + .get_port_pvid = rtl8366rb_sw_get_port_pvid, + .set_port_pvid = rtl8366rb_sw_set_port_pvid, + .reset_switch = rtl8366rb_sw_reset_switch, +}; + +static int rtl8366rb_switch_init(struct rtl8366rb *rtl) +{ + struct switch_dev *dev = &rtl->dev; + int err; + + memcpy(dev, &rtl8366_switch_dev, sizeof(struct switch_dev)); + dev->priv = rtl; + dev->devname = dev_name(rtl->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(rtl->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8366rb_switch_cleanup(struct rtl8366rb *rtl) +{ + unregister_switch(&rtl->dev); +} + +static int rtl8366rb_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366rb *rtl = bus->priv; + u32 val = 0; + int err; + + err = rtl8366rb_read_phy_reg(rtl, addr, 0, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8366rb_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366rb *rtl = bus->priv; + u32 t; + int err; + + err = rtl8366rb_write_phy_reg(rtl, addr, 0, reg, val); + /* flush write */ + (void) rtl8366rb_read_phy_reg(rtl, addr, 0, reg, &t); + + return err; +} + +static int rtl8366rb_mii_init(struct rtl8366rb *rtl) +{ + int ret; + int i; + + rtl->mii_bus = mdiobus_alloc(); + if (rtl->mii_bus == NULL) { + ret = -ENOMEM; + goto err; + } + + rtl->mii_bus->priv = (void *) rtl; + rtl->mii_bus->name = "rtl8366-rtl"; + rtl->mii_bus->read = rtl8366rb_mii_read; + rtl->mii_bus->write = rtl8366rb_mii_write; + snprintf(rtl->mii_bus->id, MII_BUS_ID_SIZE, "%s", + dev_name(rtl->parent)); + rtl->mii_bus->parent = rtl->parent; + rtl->mii_bus->phy_mask = ~(0x1f); + rtl->mii_bus->irq = rtl->mii_irq; + for (i = 0; i < PHY_MAX_ADDR; i++) + rtl->mii_irq[i] = PHY_POLL; + + ret = mdiobus_register(rtl->mii_bus); + if (ret) + goto err_free; + + return 0; + + err_free: + mdiobus_free(rtl->mii_bus); + err: + return ret; +} + +static void rtl8366rb_mii_cleanup(struct rtl8366rb *rtl) +{ + mdiobus_unregister(rtl->mii_bus); + mdiobus_free(rtl->mii_bus); +} + +static int rtl8366rb_mii_bus_match(struct mii_bus *bus) +{ + return (bus->read == rtl8366rb_mii_read && + bus->write == rtl8366rb_mii_write); +} + +static int rtl8366rb_setup(struct rtl8366rb *rtl) +{ + struct rtl8366_smi *smi = &rtl->smi; + u32 chip_id = 0; + u32 chip_ver = 0; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_ID_REG, &chip_id); + if (ret) { + dev_err(rtl->parent, "unable to read chip id\n"); + return ret; + } + + switch (chip_id) { + case RTL8366S_CHIP_ID_8366: + break; + default: + dev_err(rtl->parent, "unknown chip id (%04x)\n", chip_id); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_VERSION_CTRL_REG, + &chip_ver); + if (ret) { + dev_err(rtl->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(rtl->parent, "RTL%04x ver. %u chip found\n", + chip_id, chip_ver & RTL8366S_CHIP_VERSION_MASK); + + ret = rtl8366rb_reset_chip(rtl); + if (ret) + return ret; + + rtl8366rb_debugfs_init(rtl); + return 0; +} + +static int __init rtl8366rb_probe(struct platform_device *pdev) +{ + static int rtl8366_smi_version_printed; + struct rtl8366rb_platform_data *pdata; + struct rtl8366rb *rtl; + struct rtl8366_smi *smi; + int err; + + if (!rtl8366_smi_version_printed++) + printk(KERN_NOTICE RTL8366S_DRIVER_DESC + " version " RTL8366S_DRIVER_VER"\n"); + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "no platform data specified\n"); + err = -EINVAL; + goto err_out; + } + + rtl = kzalloc(sizeof(*rtl), GFP_KERNEL); + if (!rtl) { + dev_err(&pdev->dev, "no memory for private data\n"); + err = -ENOMEM; + goto err_out; + } + + rtl->parent = &pdev->dev; + + smi = &rtl->smi; + smi->parent = &pdev->dev; + smi->gpio_sda = pdata->gpio_sda; + smi->gpio_sck = pdata->gpio_sck; + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_rtl; + + platform_set_drvdata(pdev, rtl); + + err = rtl8366rb_setup(rtl); + if (err) + goto err_clear_drvdata; + + err = rtl8366rb_mii_init(rtl); + if (err) + goto err_clear_drvdata; + + err = rtl8366rb_switch_init(rtl); + if (err) + goto err_mii_cleanup; + + return 0; + + err_mii_cleanup: + rtl8366rb_mii_cleanup(rtl); + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_rtl: + kfree(rtl); + err_out: + return err; +} + +static int rtl8366rb_phy_config_init(struct phy_device *phydev) +{ + if (!rtl8366rb_mii_bus_match(phydev->bus)) + return -EINVAL; + + return 0; +} + +static int rtl8366rb_phy_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static struct phy_driver rtl8366rb_phy_driver = { + .phy_id = 0x001cc960, + .name = "Realtek RTL8366RB", + .phy_id_mask = 0x1ffffff0, + .features = PHY_GBIT_FEATURES, + .config_aneg = rtl8366rb_phy_config_aneg, + .config_init = rtl8366rb_phy_config_init, + .read_status = genphy_read_status, + .driver = { + .owner = THIS_MODULE, + }, +}; + +static int __devexit rtl8366rb_remove(struct platform_device *pdev) +{ + struct rtl8366rb *rtl = platform_get_drvdata(pdev); + + if (rtl) { + rtl8366rb_switch_cleanup(rtl); + rtl8366rb_debugfs_remove(rtl); + rtl8366rb_mii_cleanup(rtl); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(&rtl->smi); + kfree(rtl); + } + + return 0; +} + +static struct platform_driver rtl8366rb_driver = { + .driver = { + .name = RTL8366RB_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = rtl8366rb_probe, + .remove = __devexit_p(rtl8366rb_remove), +}; + +static int __init rtl8366rb_module_init(void) +{ + int ret; + ret = platform_driver_register(&rtl8366rb_driver); + if (ret) + return ret; + + ret = phy_driver_register(&rtl8366rb_phy_driver); + if (ret) + goto err_platform_unregister; + + return 0; + + err_platform_unregister: + platform_driver_unregister(&rtl8366rb_driver); + return ret; +} +module_init(rtl8366rb_module_init); + +static void __exit rtl8366rb_module_exit(void) +{ + phy_driver_unregister(&rtl8366rb_phy_driver); + platform_driver_unregister(&rtl8366rb_driver); +} +module_exit(rtl8366rb_module_exit); + +MODULE_DESCRIPTION(RTL8366S_DRIVER_DESC); +MODULE_VERSION(RTL8366S_DRIVER_VER); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_AUTHOR("Antti Seppälä "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8366RB_DRIVER_NAME); diff --git a/target/linux/generic-2.6/files/include/linux/rtl8366rb.h b/target/linux/generic-2.6/files/include/linux/rtl8366rb.h new file mode 100644 index 000000000..053e2ec04 --- /dev/null +++ b/target/linux/generic-2.6/files/include/linux/rtl8366rb.h @@ -0,0 +1,21 @@ +/* + * Platform data definition for the Realtek RTL8366S ethernet switch driver + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef _RTL8366RB_H +#define _RTL8366RB_H + +#define RTL8366RB_DRIVER_NAME "rtl8366rb" + +struct rtl8366rb_platform_data { + unsigned gpio_sda; + unsigned gpio_sck; +}; + +#endif /* _RTL8366RB_SMI_H */ diff --git a/target/linux/generic-2.6/patches-2.6.30/065-rootfs_split.patch b/target/linux/generic-2.6/patches-2.6.30/065-rootfs_split.patch index 824e3df10..34c1f5add 100644 --- a/target/linux/generic-2.6/patches-2.6.30/065-rootfs_split.patch +++ b/target/linux/generic-2.6/patches-2.6.30/065-rootfs_split.patch @@ -441,7 +441,7 @@ if (devt) { bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ); } -@@ -263,17 +276,97 @@ static struct block2mtd_dev *add_device( +@@ -263,17 +276,98 @@ static struct block2mtd_dev *add_device( #endif if (IS_ERR(bdev)) { @@ -505,9 +505,10 @@ + bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ); + if (!bdev || !bdev->bd_disk) + err = -EINVAL; -+ else { ++#ifndef CONFIG_MTD_BLOCK2MTD_MODULE ++ else + err = rescan_partitions(bdev->bd_disk, bdev); -+ } ++#endif + if (bdev) + close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); + @@ -542,7 +543,7 @@ if (!mtdname) mtdname = devname; -@@ -297,6 +390,7 @@ static struct block2mtd_dev *add_device( +@@ -297,6 +391,7 @@ static struct block2mtd_dev *add_device( dev->mtd.read = block2mtd_read; dev->mtd.priv = dev; dev->mtd.owner = THIS_MODULE; diff --git a/target/linux/generic-2.6/patches-2.6.30/640-br2684_backport_routed.patch b/target/linux/generic-2.6/patches-2.6.30/640-br2684_backport_routed.patch new file mode 100644 index 000000000..d925144fa --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.30/640-br2684_backport_routed.patch @@ -0,0 +1,42 @@ +commit 2e302ebfeac04beb5a5d6af1ac583c6a1fb76d1a +Author: chas williams - CONTRACTOR +Date: Fri Dec 4 11:06:32 2009 +0000 + + atm: [br2684] allow routed mode operation again + + in routed mode, we don't have a hardware address so netdev_ops doesnt + need to validate our hardware address via .ndo_validate_addr + + Reported-by: Manuel Fuentes + Signed-off-by: Chas Williams - CONTRACTOR + Signed-off-by: David S. Miller + +--- a/net/atm/br2684.c ++++ b/net/atm/br2684.c +@@ -544,6 +544,12 @@ static const struct net_device_ops br268 + .ndo_validate_addr = eth_validate_addr, + }; + ++static const struct net_device_ops br2684_netdev_ops_routed = { ++ .ndo_start_xmit = br2684_start_xmit, ++ .ndo_set_mac_address = br2684_mac_addr, ++ .ndo_change_mtu = eth_change_mtu ++}; ++ + static void br2684_setup(struct net_device *netdev) + { + struct br2684_dev *brdev = BRPRIV(netdev); +@@ -559,11 +565,10 @@ static void br2684_setup(struct net_devi + static void br2684_setup_routed(struct net_device *netdev) + { + struct br2684_dev *brdev = BRPRIV(netdev); +- brdev->net_dev = netdev; + ++ brdev->net_dev = netdev; + netdev->hard_header_len = 0; +- +- netdev->netdev_ops = &br2684_netdev_ops; ++ netdev->netdev_ops = &br2684_netdev_ops_routed; + netdev->addr_len = 0; + netdev->mtu = 1500; + netdev->type = ARPHRD_PPP; diff --git a/target/linux/generic-2.6/patches-2.6.30/691-phy_rtl8366.patch b/target/linux/generic-2.6/patches-2.6.30/691-phy_rtl8366.patch index 6223f00fe..4ce0520b1 100644 --- a/target/linux/generic-2.6/patches-2.6.30/691-phy_rtl8366.patch +++ b/target/linux/generic-2.6/patches-2.6.30/691-phy_rtl8366.patch @@ -1,6 +1,6 @@ --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig -@@ -135,4 +135,25 @@ config MDIO_GPIO +@@ -135,4 +135,29 @@ config MDIO_GPIO To compile this driver as a module, choose M here: the module will be called mdio-gpio. @@ -17,9 +17,13 @@ + tristate "Driver for the Realtek RTL8366S switch" + select SWCONFIG + ++config RTL8366RB_PHY ++ tristate "Driver for the Realtek RTL8366RB switch" ++ select SWCONFIG ++ +config RTL8366S_PHY_DEBUG_FS -+ bool "RTL8366S switch driver DEBUG_FS support" -+ depends on RTL8366S_PHY ++ bool "RTL8366 switch driver DEBUG_FS support" ++ depends on RTL8366S_PHY || RTL8366RB_PHY + depends on DEBUG_FS + default n + @@ -28,12 +32,13 @@ endif # PHYLIB --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile -@@ -19,6 +19,8 @@ obj-$(CONFIG_IP175C_PHY) += ip175c.o +@@ -19,6 +19,9 @@ obj-$(CONFIG_IP175C_PHY) += ip175c.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_AR8216_PHY) += ar8216.o obj-$(CONFIG_RTL8306_PHY) += rtl8306.o +obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o +obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o ++obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_FIXED_PHY) += fixed.o obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic-2.6/patches-2.6.31/065-rootfs_split.patch b/target/linux/generic-2.6/patches-2.6.31/065-rootfs_split.patch index 50ca25ce6..7956baf9b 100644 --- a/target/linux/generic-2.6/patches-2.6.31/065-rootfs_split.patch +++ b/target/linux/generic-2.6/patches-2.6.31/065-rootfs_split.patch @@ -434,7 +434,7 @@ if (devt) { bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ); } -@@ -263,17 +276,97 @@ static struct block2mtd_dev *add_device( +@@ -263,17 +276,98 @@ static struct block2mtd_dev *add_device( #endif if (IS_ERR(bdev)) { @@ -498,9 +498,10 @@ + bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ); + if (!bdev || !bdev->bd_disk) + err = -EINVAL; -+ else { ++#ifndef CONFIG_MTD_BLOCK2MTD_MODULE ++ else + err = rescan_partitions(bdev->bd_disk, bdev); -+ } ++#endif + if (bdev) + close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); + @@ -535,7 +536,7 @@ if (!mtdname) mtdname = devname; -@@ -297,6 +390,7 @@ static struct block2mtd_dev *add_device( +@@ -297,6 +391,7 @@ static struct block2mtd_dev *add_device( dev->mtd.read = block2mtd_read; dev->mtd.priv = dev; dev->mtd.owner = THIS_MODULE; diff --git a/target/linux/generic-2.6/patches-2.6.31/640-br2684_backport_routed.patch b/target/linux/generic-2.6/patches-2.6.31/640-br2684_backport_routed.patch new file mode 100644 index 000000000..1623e7f9b --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.31/640-br2684_backport_routed.patch @@ -0,0 +1,42 @@ +commit 2e302ebfeac04beb5a5d6af1ac583c6a1fb76d1a +Author: chas williams - CONTRACTOR +Date: Fri Dec 4 11:06:32 2009 +0000 + + atm: [br2684] allow routed mode operation again + + in routed mode, we don't have a hardware address so netdev_ops doesnt + need to validate our hardware address via .ndo_validate_addr + + Reported-by: Manuel Fuentes + Signed-off-by: Chas Williams - CONTRACTOR + Signed-off-by: David S. Miller + +--- a/net/atm/br2684.c ++++ b/net/atm/br2684.c +@@ -536,6 +536,12 @@ static const struct net_device_ops br268 + .ndo_validate_addr = eth_validate_addr, + }; + ++static const struct net_device_ops br2684_netdev_ops_routed = { ++ .ndo_start_xmit = br2684_start_xmit, ++ .ndo_set_mac_address = br2684_mac_addr, ++ .ndo_change_mtu = eth_change_mtu ++}; ++ + static void br2684_setup(struct net_device *netdev) + { + struct br2684_dev *brdev = BRPRIV(netdev); +@@ -551,11 +557,10 @@ static void br2684_setup(struct net_devi + static void br2684_setup_routed(struct net_device *netdev) + { + struct br2684_dev *brdev = BRPRIV(netdev); +- brdev->net_dev = netdev; + ++ brdev->net_dev = netdev; + netdev->hard_header_len = 0; +- +- netdev->netdev_ops = &br2684_netdev_ops; ++ netdev->netdev_ops = &br2684_netdev_ops_routed; + netdev->addr_len = 0; + netdev->mtu = 1500; + netdev->type = ARPHRD_PPP; diff --git a/target/linux/generic-2.6/patches-2.6.31/691-phy_rtl8366.patch b/target/linux/generic-2.6/patches-2.6.31/691-phy_rtl8366.patch index 6223f00fe..4ce0520b1 100644 --- a/target/linux/generic-2.6/patches-2.6.31/691-phy_rtl8366.patch +++ b/target/linux/generic-2.6/patches-2.6.31/691-phy_rtl8366.patch @@ -1,6 +1,6 @@ --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig -@@ -135,4 +135,25 @@ config MDIO_GPIO +@@ -135,4 +135,29 @@ config MDIO_GPIO To compile this driver as a module, choose M here: the module will be called mdio-gpio. @@ -17,9 +17,13 @@ + tristate "Driver for the Realtek RTL8366S switch" + select SWCONFIG + ++config RTL8366RB_PHY ++ tristate "Driver for the Realtek RTL8366RB switch" ++ select SWCONFIG ++ +config RTL8366S_PHY_DEBUG_FS -+ bool "RTL8366S switch driver DEBUG_FS support" -+ depends on RTL8366S_PHY ++ bool "RTL8366 switch driver DEBUG_FS support" ++ depends on RTL8366S_PHY || RTL8366RB_PHY + depends on DEBUG_FS + default n + @@ -28,12 +32,13 @@ endif # PHYLIB --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile -@@ -19,6 +19,8 @@ obj-$(CONFIG_IP175C_PHY) += ip175c.o +@@ -19,6 +19,9 @@ obj-$(CONFIG_IP175C_PHY) += ip175c.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_AR8216_PHY) += ar8216.o obj-$(CONFIG_RTL8306_PHY) += rtl8306.o +obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o +obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o ++obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_FIXED_PHY) += fixed.o obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic-2.6/patches-2.6.32/065-rootfs_split.patch b/target/linux/generic-2.6/patches-2.6.32/065-rootfs_split.patch index 307e5ee34..22b3f5e90 100644 --- a/target/linux/generic-2.6/patches-2.6.32/065-rootfs_split.patch +++ b/target/linux/generic-2.6/patches-2.6.32/065-rootfs_split.patch @@ -434,7 +434,7 @@ if (devt) { bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ); } -@@ -263,17 +276,97 @@ static struct block2mtd_dev *add_device( +@@ -263,17 +276,98 @@ static struct block2mtd_dev *add_device( #endif if (IS_ERR(bdev)) { @@ -498,9 +498,10 @@ + bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ); + if (!bdev || !bdev->bd_disk) + err = -EINVAL; -+ else { ++#ifndef CONFIG_MTD_BLOCK2MTD_MODULE ++ else + err = rescan_partitions(bdev->bd_disk, bdev); -+ } ++#endif + if (bdev) + close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); + @@ -535,7 +536,7 @@ if (!mtdname) mtdname = devname; -@@ -297,6 +390,7 @@ static struct block2mtd_dev *add_device( +@@ -297,6 +391,7 @@ static struct block2mtd_dev *add_device( dev->mtd.read = block2mtd_read; dev->mtd.priv = dev; dev->mtd.owner = THIS_MODULE; diff --git a/target/linux/generic-2.6/patches-2.6.32/221-binfmt_elf_gcc4.1.patch b/target/linux/generic-2.6/patches-2.6.32/221-binfmt_elf_gcc4.1.patch index 64f28d80f..694737e40 100644 --- a/target/linux/generic-2.6/patches-2.6.32/221-binfmt_elf_gcc4.1.patch +++ b/target/linux/generic-2.6/patches-2.6.32/221-binfmt_elf_gcc4.1.patch @@ -1,6 +1,6 @@ --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c -@@ -1170,7 +1170,7 @@ +@@ -1170,7 +1170,7 @@ static unsigned long vma_dump_size(struc if (FILTER(ELF_HEADERS) && vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) { u32 __user *header = (u32 __user *) vma->vm_start; diff --git a/target/linux/generic-2.6/patches-2.6.32/240-packet_socket_type.patch b/target/linux/generic-2.6/patches-2.6.32/240-packet_socket_type.patch index a03d69957..864f5733a 100644 --- a/target/linux/generic-2.6/patches-2.6.32/240-packet_socket_type.patch +++ b/target/linux/generic-2.6/patches-2.6.32/240-packet_socket_type.patch @@ -7,7 +7,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h -@@ -31,6 +31,8 @@ +@@ -31,6 +31,8 @@ struct sockaddr_ll /* These ones are invisible by user level */ #define PACKET_LOOPBACK 5 /* MC/BRD frame looped back */ #define PACKET_FASTROUTE 6 /* Fastrouted frame */ @@ -16,7 +16,7 @@ Signed-off-by: Felix Fietkau /* Packet socket options */ -@@ -48,6 +50,7 @@ +@@ -48,6 +50,7 @@ struct sockaddr_ll #define PACKET_RESERVE 12 #define PACKET_TX_RING 13 #define PACKET_LOSS 14 @@ -26,7 +26,7 @@ Signed-off-by: Felix Fietkau { --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c -@@ -204,6 +204,7 @@ +@@ -204,6 +204,7 @@ struct packet_sock { unsigned int tp_reserve; unsigned int tp_loss:1; #endif @@ -34,7 +34,7 @@ Signed-off-by: Felix Fietkau }; struct packet_skb_cb { -@@ -342,6 +343,7 @@ +@@ -342,6 +343,7 @@ static int packet_rcv_spkt(struct sk_buf { struct sock *sk; struct sockaddr_pkt *spkt; @@ -42,7 +42,7 @@ Signed-off-by: Felix Fietkau /* * When we registered the protocol we saved the socket in the data -@@ -349,6 +351,7 @@ +@@ -349,6 +351,7 @@ static int packet_rcv_spkt(struct sk_buf */ sk = pt->af_packet_priv; @@ -50,7 +50,7 @@ Signed-off-by: Felix Fietkau /* * Yank back the headers [hope the device set this -@@ -361,7 +364,7 @@ +@@ -361,7 +364,7 @@ static int packet_rcv_spkt(struct sk_buf * so that this procedure is noop. */ @@ -59,7 +59,7 @@ Signed-off-by: Felix Fietkau goto out; if (dev_net(dev) != sock_net(sk)) -@@ -545,12 +548,12 @@ +@@ -545,12 +548,12 @@ static int packet_rcv(struct sk_buff *sk int skb_len = skb->len; unsigned int snaplen, res; @@ -75,7 +75,7 @@ Signed-off-by: Felix Fietkau if (dev_net(dev) != sock_net(sk)) goto drop; -@@ -667,12 +670,12 @@ +@@ -667,12 +670,12 @@ static int tpacket_rcv(struct sk_buff *s struct timeval tv; struct timespec ts; @@ -91,7 +91,7 @@ Signed-off-by: Felix Fietkau if (dev_net(dev) != sock_net(sk)) goto drop; -@@ -1390,6 +1393,7 @@ +@@ -1390,6 +1393,7 @@ static int packet_create(struct net *net spin_lock_init(&po->bind_lock); mutex_init(&po->pg_vec_lock); po->prot_hook.func = packet_rcv; @@ -99,7 +99,7 @@ Signed-off-by: Felix Fietkau if (sock->type == SOCK_PACKET) po->prot_hook.func = packet_rcv_spkt; -@@ -1737,6 +1741,16 @@ +@@ -1737,6 +1741,16 @@ packet_setsockopt(struct socket *sock, i ret = packet_mc_drop(sk, &mreq); return ret; } @@ -116,7 +116,7 @@ Signed-off-by: Felix Fietkau #ifdef CONFIG_PACKET_MMAP case PACKET_RX_RING: -@@ -1882,6 +1896,13 @@ +@@ -1882,6 +1896,13 @@ static int packet_getsockopt(struct sock data = &val; break; diff --git a/target/linux/generic-2.6/patches-2.6.32/640-br2684_backport_routed.patch b/target/linux/generic-2.6/patches-2.6.32/640-br2684_backport_routed.patch new file mode 100644 index 000000000..28dd74dd7 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.32/640-br2684_backport_routed.patch @@ -0,0 +1,42 @@ +commit 2e302ebfeac04beb5a5d6af1ac583c6a1fb76d1a +Author: chas williams - CONTRACTOR +Date: Fri Dec 4 11:06:32 2009 +0000 + + atm: [br2684] allow routed mode operation again + + in routed mode, we don't have a hardware address so netdev_ops doesnt + need to validate our hardware address via .ndo_validate_addr + + Reported-by: Manuel Fuentes + Signed-off-by: Chas Williams - CONTRACTOR + Signed-off-by: David S. Miller + +--- a/net/atm/br2684.c ++++ b/net/atm/br2684.c +@@ -554,6 +554,12 @@ static const struct net_device_ops br268 + .ndo_validate_addr = eth_validate_addr, + }; + ++static const struct net_device_ops br2684_netdev_ops_routed = { ++ .ndo_start_xmit = br2684_start_xmit, ++ .ndo_set_mac_address = br2684_mac_addr, ++ .ndo_change_mtu = eth_change_mtu ++}; ++ + static void br2684_setup(struct net_device *netdev) + { + struct br2684_dev *brdev = BRPRIV(netdev); +@@ -569,11 +575,10 @@ static void br2684_setup(struct net_devi + static void br2684_setup_routed(struct net_device *netdev) + { + struct br2684_dev *brdev = BRPRIV(netdev); +- brdev->net_dev = netdev; + ++ brdev->net_dev = netdev; + netdev->hard_header_len = 0; +- +- netdev->netdev_ops = &br2684_netdev_ops; ++ netdev->netdev_ops = &br2684_netdev_ops_routed; + netdev->addr_len = 0; + netdev->mtu = 1500; + netdev->type = ARPHRD_PPP; diff --git a/target/linux/generic-2.6/patches-2.6.32/691-phy_rtl8366.patch b/target/linux/generic-2.6/patches-2.6.32/691-phy_rtl8366.patch index 2f6b3c49f..db29760c5 100644 --- a/target/linux/generic-2.6/patches-2.6.32/691-phy_rtl8366.patch +++ b/target/linux/generic-2.6/patches-2.6.32/691-phy_rtl8366.patch @@ -1,6 +1,6 @@ --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig -@@ -141,4 +141,25 @@ config MDIO_GPIO +@@ -141,4 +141,29 @@ config MDIO_GPIO To compile this driver as a module, choose M here: the module will be called mdio-gpio. @@ -17,9 +17,13 @@ + tristate "Driver for the Realtek RTL8366S switch" + select SWCONFIG + ++config RTL8366RB_PHY ++ tristate "Driver for the Realtek RTL8366RB switch" ++ select SWCONFIG ++ +config RTL8366S_PHY_DEBUG_FS -+ bool "RTL8366S switch driver DEBUG_FS support" -+ depends on RTL8366S_PHY ++ bool "RTL8366 switch driver DEBUG_FS support" ++ depends on RTL8366S_PHY || RTL8366RB_PHY + depends on DEBUG_FS + default n + @@ -28,12 +32,13 @@ endif # PHYLIB --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile -@@ -20,6 +20,8 @@ obj-$(CONFIG_IP175C_PHY) += ip175c.o +@@ -20,6 +20,9 @@ obj-$(CONFIG_IP175C_PHY) += ip175c.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_AR8216_PHY) += ar8216.o obj-$(CONFIG_RTL8306_PHY) += rtl8306.o +obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o +obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o ++obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_FIXED_PHY) += fixed.o obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic-2.6/patches-2.6.32/980-vm_exports.patch b/target/linux/generic-2.6/patches-2.6.32/980-vm_exports.patch index ca70efe0e..efaa20976 100644 --- a/target/linux/generic-2.6/patches-2.6.32/980-vm_exports.patch +++ b/target/linux/generic-2.6/patches-2.6.32/980-vm_exports.patch @@ -1,6 +1,6 @@ --- a/mm/shmem.c +++ b/mm/shmem.c -@@ -2608,6 +2608,16 @@ +@@ -2608,6 +2608,16 @@ int shmem_lock(struct file *file, int lo /* common code */ @@ -17,7 +17,7 @@ /** * shmem_file_setup - get an unlinked file living in tmpfs * @name: name for dentry (to be seen in /proc//maps -@@ -2687,9 +2697,6 @@ +@@ -2687,9 +2697,6 @@ int shmem_zero_setup(struct vm_area_stru if (IS_ERR(file)) return PTR_ERR(file); @@ -30,7 +30,7 @@ } --- a/fs/file.c +++ b/fs/file.c -@@ -271,6 +271,7 @@ +@@ -271,6 +271,7 @@ int expand_files(struct files_struct *fi /* All good, so we try */ return expand_fdtable(files, nr); } @@ -40,7 +40,7 @@ { --- a/kernel/exit.c +++ b/kernel/exit.c -@@ -507,6 +507,7 @@ +@@ -507,6 +507,7 @@ struct files_struct *get_files_struct(st return files; } @@ -48,7 +48,7 @@ void put_files_struct(struct files_struct *files) { -@@ -526,6 +527,7 @@ +@@ -526,6 +527,7 @@ void put_files_struct(struct files_struc free_fdtable(fdt); } } @@ -58,7 +58,7 @@ { --- a/kernel/fork.c +++ b/kernel/fork.c -@@ -168,6 +168,7 @@ +@@ -168,6 +168,7 @@ void __put_task_struct(struct task_struc if (!profile_handoff_task(tsk)) free_task(tsk); } @@ -68,7 +68,7 @@ * macro override instead of weak attribute alias, to workaround --- a/kernel/sched.c +++ b/kernel/sched.c -@@ -6093,6 +6093,7 @@ +@@ -6093,6 +6093,7 @@ int can_nice(const struct task_struct *p return (nice_rlim <= p->signal->rlim[RLIMIT_NICE].rlim_cur || capable(CAP_SYS_NICE)); } @@ -78,7 +78,7 @@ --- a/mm/memory.c +++ b/mm/memory.c -@@ -1100,6 +1100,7 @@ +@@ -1100,6 +1100,7 @@ unsigned long zap_page_range(struct vm_a tlb_finish_mmu(tlb, address, end); return end; } @@ -86,7 +86,7 @@ /** * zap_vma_ptes - remove ptes mapping the vma -@@ -2486,6 +2487,7 @@ +@@ -2486,6 +2487,7 @@ int vmtruncate_range(struct inode *inode return 0; } @@ -96,7 +96,7 @@ * We enter with non-exclusive mmap_sem (to exclude vma changes, --- a/mm/vmalloc.c +++ b/mm/vmalloc.c -@@ -1172,6 +1172,7 @@ +@@ -1172,6 +1172,7 @@ void unmap_kernel_range(unsigned long ad vunmap_page_range(addr, end); flush_tlb_kernel_range(addr, end); } @@ -104,7 +104,7 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages) { -@@ -1287,6 +1288,7 @@ +@@ -1287,6 +1288,7 @@ struct vm_struct *get_vm_area(unsigned l return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END, -1, GFP_KERNEL, __builtin_return_address(0)); } @@ -114,7 +114,7 @@ void *caller) --- a/include/linux/mm.h +++ b/include/linux/mm.h -@@ -713,6 +713,7 @@ +@@ -713,6 +713,7 @@ extern void show_free_areas(void); int shmem_lock(struct file *file, int lock, struct user_struct *user); struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags); @@ -124,7 +124,7 @@ #ifndef CONFIG_MMU --- a/kernel/signal.c +++ b/kernel/signal.c -@@ -1070,6 +1070,7 @@ +@@ -1070,6 +1070,7 @@ struct sighand_struct *lock_task_sighand return sighand; } diff --git a/target/linux/generic-2.6/patches-2.6.32/999-use_preinit_as_init.patch b/target/linux/generic-2.6/patches-2.6.32/999-use_preinit_as_init.patch index 33943fe2d..0a52a87e8 100644 --- a/target/linux/generic-2.6/patches-2.6.32/999-use_preinit_as_init.patch +++ b/target/linux/generic-2.6/patches-2.6.32/999-use_preinit_as_init.patch @@ -1,6 +1,6 @@ --- a/init/main.c +++ b/init/main.c -@@ -836,10 +836,7 @@ +@@ -836,10 +836,7 @@ static noinline int init_post(void) printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command); } diff --git a/target/linux/mpc83xx/config-2.6.32 b/target/linux/mpc83xx/config-2.6.32 index 9a30fe0e4..030a7b411 100644 --- a/target/linux/mpc83xx/config-2.6.32 +++ b/target/linux/mpc83xx/config-2.6.32 @@ -24,10 +24,11 @@ CONFIG_AUDIT_ARCH=y CONFIG_BITREVERSE=y # CONFIG_BOOTX_TEXT is not set CONFIG_BOUNCE=y +CONFIG_BUBBATWO=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_CFG80211_DEFAULT_PS_VALUE=0 -CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="console=ttyS0,115200" +CONFIG_CMDLINE_BOOL=y CONFIG_DECOMPRESS_LZMA=y CONFIG_DEFAULT_UIMAGE=y CONFIG_DEVPORT=y @@ -46,8 +47,8 @@ CONFIG_FSL_SOC=y # CONFIG_FSNOTIFY is not set CONFIG_GENERIC_ATOMIC64=y CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_FIND_LAST_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y @@ -85,14 +86,14 @@ CONFIG_HAVE_OPROFILE=y CONFIG_HAVE_PERF_EVENTS=y # CONFIG_HAVE_SETUP_PER_CPU_AREA is not set CONFIG_HW_RANDOM=y -# CONFIG_HZ_100 is not set CONFIG_HZ=250 +# CONFIG_HZ_100 is not set CONFIG_HZ_250=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_IOMMU_HELPER is not set CONFIG_IPIC=y -CONFIG_IRQ_PER_CPU=y # CONFIG_IRQSTACKS is not set +CONFIG_IRQ_PER_CPU=y CONFIG_ISA_DMA_API=y CONFIG_KERNEL_START=0xc0000000 # CONFIG_KMETER1 is not set @@ -102,7 +103,7 @@ CONFIG_MAX_ACTIVE_REGIONS=32 # CONFIG_MMIO_NVRAM is not set # CONFIG_MPC5121_ADS is not set # CONFIG_MPC5121_GENERIC is not set -# CONFIG_MPC831x_RDB is not set +CONFIG_MPC831x_RDB=y # CONFIG_MPC832x_MDS is not set # CONFIG_MPC832x_RDB is not set # CONFIG_MPC834x_ITX is not set @@ -114,31 +115,32 @@ CONFIG_MPC837x_RDB=y # CONFIG_MPC8xxx_GPIO is not set # CONFIG_MPIC is not set # CONFIG_MPIC_WEIRD is not set +CONFIG_MTD_NAND=y # CONFIG_MTD_NAND_FSL_ELBC is not set # CONFIG_MTD_NAND_FSL_UPM is not set CONFIG_MTD_NAND_RB_PPC=y -CONFIG_MTD_NAND=y CONFIG_MTD_OF_PARTS=y CONFIG_MTD_PHYSMAP_OF=y # CONFIG_MV643XX_ETH is not set # CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set +CONFIG_OF=y CONFIG_OF_DEVICE=y CONFIG_OF_GPIO=y CONFIG_OF_MDIO=y -CONFIG_OF=y CONFIG_PAGEFLAGS_EXTENDED=y CONFIG_PAGE_OFFSET=0xc0000000 CONFIG_PATA_RB_PPC=m +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIEPORTBUS=y +# CONFIG_PCIE_ECRC is not set CONFIG_PCI_DISABLE_COMMON_QUIRKS=y CONFIG_PCI_DOMAINS=y -# CONFIG_PCIEAER_INJECT is not set -CONFIG_PCIEAER=y -# CONFIG_PCIE_ECRC is not set -CONFIG_PCIEPORTBUS=y # CONFIG_PERF_COUNTERS is not set # CONFIG_PERF_EVENTS is not set CONFIG_PHYLIB=y CONFIG_PHYSICAL_START=0x00000000 +CONFIG_PPC=y CONFIG_PPC32=y # CONFIG_PPC64 is not set # CONFIG_PPC_82xx is not set @@ -147,8 +149,8 @@ CONFIG_PPC_83xx=y # CONFIG_PPC_86xx is not set # CONFIG_PPC_8xx is not set # CONFIG_PPC_970_NAP is not set -CONFIG_PPC_BOOK3S_32=y CONFIG_PPC_BOOK3S=y +CONFIG_PPC_BOOK3S_32=y # CONFIG_PPC_CELL is not set # CONFIG_PPC_CELL_NATIVE is not set # CONFIG_PPC_CHRP is not set @@ -166,17 +168,17 @@ CONFIG_PPC_LIB_RHEAP=y # CONFIG_PPC_MM_SLICES is not set # CONFIG_PPC_MPC106 is not set # CONFIG_PPC_MPC52xx is not set +CONFIG_PPC_MPC831x=y CONFIG_PPC_MPC834x=y CONFIG_PPC_MPC837x=y -CONFIG_PPC_OF_BOOT_TRAMPOLINE=y CONFIG_PPC_OF=y +CONFIG_PPC_OF_BOOT_TRAMPOLINE=y CONFIG_PPC_PCI_CHOICE=y # CONFIG_PPC_PMAC is not set # CONFIG_PPC_RTAS is not set -CONFIG_PPC_STD_MMU_32=y CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y CONFIG_PPC_UDBG_16550=y -CONFIG_PPC=y # CONFIG_PQ2ADS is not set CONFIG_PRINT_STACK_DEPTH=64 CONFIG_PROC_DEVICETREE=y @@ -203,6 +205,8 @@ CONFIG_TASK_SIZE=0xc0000000 # CONFIG_TREE_PREEMPT_RCU is not set CONFIG_TREE_RCU=y # CONFIG_UCC_GETH is not set +CONFIG_VITESSE_PHY=y +CONFIG_VITESSE_PHY_8601_SKEW=y CONFIG_WORD_SIZE=32 # CONFIG_XILINX_EMACLITE is not set # CONFIG_YAFFS_9BYTE_TAGS is not set diff --git a/target/linux/mpc83xx/image/Makefile b/target/linux/mpc83xx/image/Makefile index 9b241919f..0d5c380f8 100644 --- a/target/linux/mpc83xx/image/Makefile +++ b/target/linux/mpc83xx/image/Makefile @@ -9,7 +9,7 @@ include $(INCLUDE_DIR)/image.mk define Image/Prepare - $(LINUX_DIR)/scripts/dtc/dtc -O dtb -R 4 -S 0x20000 $(LINUX_DIR)/arch/powerpc/boot/dts/mpc8377_wlan.dts > $(BIN_DIR)/openwrt-mpc8377_wlan.dtb + $(LINUX_DIR)/scripts/dtc/dtc -O dtb -R 4 -S 0x20000 $(LINUX_DIR)/arch/powerpc/boot/dts/mpc8377_wlan.dts > $(BIN_DIR)/openwrt-mpc83xx-mpc8377_wlan.dtb endef define Image/BuildKernel diff --git a/target/linux/mpc83xx/patches-2.6.32/100-vitesse_8601.patch b/target/linux/mpc83xx/patches-2.6.32/100-vitesse_8601.patch new file mode 100644 index 000000000..0eb2880f9 --- /dev/null +++ b/target/linux/mpc83xx/patches-2.6.32/100-vitesse_8601.patch @@ -0,0 +1,116 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -51,6 +51,12 @@ config VITESSE_PHY + ---help--- + Currently supports the vsc8244 + ++config VITESSE_PHY_8601_SKEW ++ bool "Enable skew timing to vsc8601" ++ depends on VITESSE_PHY ++ ---help--- ++ Apply clock timing adjustments for vsc8601 ++ + config SMSC_PHY + tristate "Drivers for SMSC PHYs" + ---help--- +--- a/drivers/net/phy/vitesse.c ++++ b/drivers/net/phy/vitesse.c +@@ -26,6 +26,11 @@ + #define MII_VSC8244_EXTCON1_TX_SKEW 0x0800 + #define MII_VSC8244_EXTCON1_RX_SKEW 0x0200 + ++/* EXT_CON1 Register values for VSC8601 */ ++#define MII_VSC8601_EXTCON1_INIT 0x0000 ++#define MII_VSC8601_EXTCON1_SKEW 0x0100 ++#define MII_VSC8601_EXTCON1_ACTIPHY 0x0020 ++ + /* Vitesse Interrupt Mask Register */ + #define MII_VSC8244_IMASK 0x19 + #define MII_VSC8244_IMASK_IEN 0x8000 +@@ -88,6 +93,30 @@ static int vsc824x_config_init(struct ph + return err; + } + ++static int vsc8601_config_init(struct phy_device *phydev) ++{ ++ int err; ++ int extcon; ++ ++ err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT, ++ MII_VSC8244_AUXCONSTAT_INIT); ++ ++ if (err < 0) ++ return err; ++ ++#ifdef CONFIG_VITESSE_PHY_8601_SKEW ++ extcon = phy_read(phydev, MII_VSC8244_EXT_CON1); ++ if (err < 0) ++ return err; ++ ++ extcon |= MII_VSC8601_EXTCON1_SKEW; ++ ++ err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon); ++#endif ++ ++ return err; ++} ++ + static int vsc824x_ack_interrupt(struct phy_device *phydev) + { + int err = 0; +@@ -143,6 +172,21 @@ static struct phy_driver vsc8244_driver + .driver = { .owner = THIS_MODULE,}, + }; + ++/* Vitesse 8601 */ ++static struct phy_driver vsc8601_driver = { ++ .phy_id = 0x00070420, ++ .name = "Vitesse VSC8601", ++ .phy_id_mask = 0x000ffff8, ++ .features = PHY_GBIT_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, ++ .config_init = &vsc8601_config_init, ++ .config_aneg = &genphy_config_aneg, ++ .read_status = &genphy_read_status, ++ .ack_interrupt = &vsc824x_ack_interrupt, ++ .config_intr = &vsc82xx_config_intr, ++ .driver = { .owner = THIS_MODULE,}, ++}; ++ + static int vsc8221_config_init(struct phy_device *phydev) + { + int err; +@@ -176,10 +220,23 @@ static int __init vsc82xx_init(void) + + err = phy_driver_register(&vsc8244_driver); + if (err < 0) +- return err; ++ goto err; ++ + err = phy_driver_register(&vsc8221_driver); + if (err < 0) +- phy_driver_unregister(&vsc8244_driver); ++ goto err1; ++ ++ err = phy_driver_register(&vsc8601_driver); ++ if (err < 0) ++ goto err2; ++ ++ return 0; ++ ++err2: ++ phy_driver_unregister(&vsc8221_driver); ++err1: ++ phy_driver_unregister(&vsc8244_driver); ++err: + return err; + } + +@@ -187,6 +244,7 @@ static void __exit vsc82xx_exit(void) + { + phy_driver_unregister(&vsc8244_driver); + phy_driver_unregister(&vsc8221_driver); ++ phy_driver_unregister(&vsc8601_driver); + } + + module_init(vsc82xx_init); diff --git a/target/linux/mpc83xx/patches-2.6.32/110-etsec27_war.patch b/target/linux/mpc83xx/patches-2.6.32/110-etsec27_war.patch new file mode 100644 index 000000000..111434b2c --- /dev/null +++ b/target/linux/mpc83xx/patches-2.6.32/110-etsec27_war.patch @@ -0,0 +1,18 @@ +--- a/drivers/net/gianfar.c ++++ b/drivers/net/gianfar.c +@@ -334,7 +334,14 @@ static int gfar_probe(struct of_device * + /* We need to delay at least 3 TX clocks */ + udelay(2); + +- tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); ++ /* ++ * Do not enable flow control on chips earlier than rev 1.1, ++ * because of the eTSEC27 erratum ++ */ ++ tempval = 0; ++ if (mfspr(SPRN_SVR) & 0xffff >= 0x0011) ++ tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); ++ + gfar_write(&priv->regs->maccfg1, tempval); + + /* Initialize MACCFG2. */ diff --git a/target/linux/orion/image/Makefile b/target/linux/orion/image/Makefile index 9577cd9a9..81cd67012 100644 --- a/target/linux/orion/image/Makefile +++ b/target/linux/orion/image/Makefile @@ -63,6 +63,7 @@ define Image/Build/Linksys echo ":rootfs 0 ${KDIR}/root.$1" >>"${TMP_DIR}/$2_webupgrade/$2.par" [ ! -f "$(STAGING_DIR_HOST)/share/wrt350nv2-builder/u-boot.bin" ] || ( \ echo ":u-boot 0 $(STAGING_DIR_HOST)/share/wrt350nv2-builder/u-boot.bin" >>"${TMP_DIR}/$2_webupgrade/$2.par"; ) + echo "#version 0x2020" >>"${TMP_DIR}/$2_webupgrade/$2.par" # create bin file for recovery and webupgrade image ( cd "${TMP_DIR}/$2_webupgrade"; \ "${STAGING_DIR_HOST}/bin/$2-builder" \ diff --git a/target/linux/ppc40x/Makefile b/target/linux/ppc40x/Makefile index 910dccde3..746ff3d22 100644 --- a/target/linux/ppc40x/Makefile +++ b/target/linux/ppc40x/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2008-2009 OpenWrt.org +# Copyright (C) 2008-2010 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -12,7 +12,7 @@ BOARDNAME:=AMCC/IBM PPC40x FEATURES:=squashfs CFLAGS:=-Os -pipe -funit-at-a-time -mcpu=405 -LINUX_VERSION:=2.6.30.10 +LINUX_VERSION:=2.6.32.8 include $(INCLUDE_DIR)/target.mk diff --git a/target/linux/ppc40x/config-default b/target/linux/ppc40x/config-default index 278387d27..252637a59 100644 --- a/target/linux/ppc40x/config-default +++ b/target/linux/ppc40x/config-default @@ -80,6 +80,7 @@ CONFIG_HAVE_MLOCK=y CONFIG_HAVE_OPROFILE=y # CONFIG_HAVE_SETUP_PER_CPU_AREA is not set # CONFIG_HCU4 is not set +# CONFIG_HOTFOOT is not set CONFIG_HW_RANDOM=y # CONFIG_HZ_100 is not set CONFIG_HZ=250 @@ -135,6 +136,7 @@ CONFIG_PPC4xx_PCI_EXPRESS=y # CONFIG_PPC_85xx is not set # CONFIG_PPC_8xx is not set # CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_BOOK3S_32 is not set # CONFIG_PPC_CELL is not set # CONFIG_PPC_CELL_NATIVE is not set # CONFIG_PPC_CLOCK is not set @@ -170,6 +172,7 @@ CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_SLAB is not set # CONFIG_SLOW_WORK is not set CONFIG_SLUB=y +CONFIG_SWIOTLB=y CONFIG_TASK_SIZE=0xc0000000 CONFIG_TRACING_SUPPORT=y # CONFIG_WALNUT is not set diff --git a/target/linux/ppc40x/patches/001-makalu_ppc40x_simple.patch b/target/linux/ppc40x/patches/001-makalu_ppc40x_simple.patch deleted file mode 100644 index d4497d8c1..000000000 --- a/target/linux/ppc40x/patches/001-makalu_ppc40x_simple.patch +++ /dev/null @@ -1,443 +0,0 @@ ---- a/arch/powerpc/configs/40x/makalu_defconfig -+++ b/arch/powerpc/configs/40x/makalu_defconfig -@@ -1,7 +1,7 @@ - # - # Automatically generated make config: don't edit --# Linux kernel version: 2.6.29-rc2 --# Tue Jan 20 08:17:53 2009 -+# Linux kernel version: 2.6.30-rc7 -+# Wed Jun 3 09:11:02 2009 - # - # CONFIG_PPC64 is not set - -@@ -27,6 +27,7 @@ CONFIG_GENERIC_TIME=y - CONFIG_GENERIC_TIME_VSYSCALL=y - CONFIG_GENERIC_CLOCKEVENTS=y - CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y - # CONFIG_HAVE_SETUP_PER_CPU_AREA is not set - CONFIG_IRQ_PER_CPU=y - CONFIG_STACKTRACE_SUPPORT=y -@@ -49,10 +50,12 @@ CONFIG_PPC_UDBG_16550=y - # CONFIG_GENERIC_TBSYNC is not set - CONFIG_AUDIT_ARCH=y - CONFIG_GENERIC_BUG=y -+CONFIG_DTC=y - # CONFIG_DEFAULT_UIMAGE is not set - CONFIG_PPC_DCR_NATIVE=y - # CONFIG_PPC_DCR_MMIO is not set - CONFIG_PPC_DCR=y -+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y - CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - - # -@@ -67,9 +70,19 @@ CONFIG_SWAP=y - CONFIG_SYSVIPC=y - CONFIG_SYSVIPC_SYSCTL=y - CONFIG_POSIX_MQUEUE=y -+CONFIG_POSIX_MQUEUE_SYSCTL=y - # CONFIG_BSD_PROCESS_ACCT is not set - # CONFIG_TASKSTATS is not set - # CONFIG_AUDIT is not set -+ -+# -+# RCU Subsystem -+# -+CONFIG_CLASSIC_RCU=y -+# CONFIG_TREE_RCU is not set -+# CONFIG_PREEMPT_RCU is not set -+# CONFIG_TREE_RCU_TRACE is not set -+# CONFIG_PREEMPT_RCU_TRACE is not set - # CONFIG_IKCONFIG is not set - CONFIG_LOG_BUF_SHIFT=14 - CONFIG_GROUP_SCHED=y -@@ -84,22 +97,24 @@ CONFIG_SYSFS_DEPRECATED_V2=y - # CONFIG_NAMESPACES is not set - CONFIG_BLK_DEV_INITRD=y - CONFIG_INITRAMFS_SOURCE="" -+CONFIG_RD_GZIP=y -+# CONFIG_RD_BZIP2 is not set -+# CONFIG_RD_LZMA is not set - # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set - CONFIG_SYSCTL=y -+CONFIG_ANON_INODES=y - CONFIG_EMBEDDED=y - CONFIG_SYSCTL_SYSCALL=y - CONFIG_KALLSYMS=y - CONFIG_KALLSYMS_ALL=y --CONFIG_KALLSYMS_STRIP_GENERATED=y - CONFIG_KALLSYMS_EXTRA_PASS=y -+# CONFIG_STRIP_ASM_SYMS is not set - CONFIG_HOTPLUG=y - CONFIG_PRINTK=y - CONFIG_BUG=y - CONFIG_ELF_CORE=y --CONFIG_COMPAT_BRK=y - CONFIG_BASE_FULL=y - CONFIG_FUTEX=y --CONFIG_ANON_INODES=y - CONFIG_EPOLL=y - CONFIG_SIGNALFD=y - CONFIG_TIMERFD=y -@@ -109,10 +124,12 @@ CONFIG_AIO=y - CONFIG_VM_EVENT_COUNTERS=y - CONFIG_PCI_QUIRKS=y - CONFIG_SLUB_DEBUG=y -+CONFIG_COMPAT_BRK=y - # CONFIG_SLAB is not set - CONFIG_SLUB=y - # CONFIG_SLOB is not set - # CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set - CONFIG_HAVE_OPROFILE=y - # CONFIG_KPROBES is not set - CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -@@ -120,6 +137,7 @@ CONFIG_HAVE_IOREMAP_PROT=y - CONFIG_HAVE_KPROBES=y - CONFIG_HAVE_KRETPROBES=y - CONFIG_HAVE_ARCH_TRACEHOOK=y -+# CONFIG_SLOW_WORK is not set - # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set - CONFIG_SLABINFO=y - CONFIG_RT_MUTEXES=y -@@ -132,7 +150,6 @@ CONFIG_MODULE_UNLOAD=y - # CONFIG_MODULE_SRCVERSION_ALL is not set - CONFIG_BLOCK=y - CONFIG_LBD=y --# CONFIG_BLK_DEV_IO_TRACE is not set - # CONFIG_BLK_DEV_BSG is not set - # CONFIG_BLK_DEV_INTEGRITY is not set - -@@ -148,11 +165,6 @@ CONFIG_DEFAULT_AS=y - # CONFIG_DEFAULT_CFQ is not set - # CONFIG_DEFAULT_NOOP is not set - CONFIG_DEFAULT_IOSCHED="anticipatory" --CONFIG_CLASSIC_RCU=y --# CONFIG_TREE_RCU is not set --# CONFIG_PREEMPT_RCU is not set --# CONFIG_TREE_RCU_TRACE is not set --# CONFIG_PREEMPT_RCU_TRACE is not set - # CONFIG_FREEZER is not set - CONFIG_PPC4xx_PCI_EXPRESS=y - -@@ -170,7 +182,7 @@ CONFIG_PPC4xx_PCI_EXPRESS=y - CONFIG_MAKALU=y - # CONFIG_WALNUT is not set - # CONFIG_XILINX_VIRTEX_GENERIC_BOARD is not set --# CONFIG_PPC40x_SIMPLE is not set -+CONFIG_PPC40x_SIMPLE=y - CONFIG_405EX=y - # CONFIG_IPIC is not set - # CONFIG_MPIC is not set -@@ -228,9 +240,12 @@ CONFIG_ZONE_DMA_FLAG=1 - CONFIG_BOUNCE=y - CONFIG_VIRT_TO_BUS=y - CONFIG_UNEVICTABLE_LRU=y -+CONFIG_HAVE_MLOCK=y -+CONFIG_HAVE_MLOCKED_PAGE_BIT=y - CONFIG_PPC_4K_PAGES=y - # CONFIG_PPC_16K_PAGES is not set - # CONFIG_PPC_64K_PAGES is not set -+# CONFIG_PPC_256K_PAGES is not set - CONFIG_FORCE_MAX_ZONEORDER=11 - CONFIG_PROC_DEVICETREE=y - # CONFIG_CMDLINE_BOOL is not set -@@ -255,6 +270,7 @@ CONFIG_ARCH_SUPPORTS_MSI=y - CONFIG_PCI_LEGACY=y - # CONFIG_PCI_DEBUG is not set - # CONFIG_PCI_STUB is not set -+# CONFIG_PCI_IOV is not set - # CONFIG_PCCARD is not set - # CONFIG_HOTPLUG_PCI is not set - # CONFIG_HAS_RAPIDIO is not set -@@ -272,14 +288,12 @@ CONFIG_PAGE_OFFSET=0xc0000000 - CONFIG_KERNEL_START=0xc0000000 - CONFIG_PHYSICAL_START=0x00000000 - CONFIG_TASK_SIZE=0xc0000000 --CONFIG_CONSISTENT_START=0xff100000 - CONFIG_CONSISTENT_SIZE=0x00200000 - CONFIG_NET=y - - # - # Networking options - # --CONFIG_COMPAT_NET_DEV_OPS=y - CONFIG_PACKET=y - # CONFIG_PACKET_MMAP is not set - CONFIG_UNIX=y -@@ -329,6 +343,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" - # CONFIG_LAPB is not set - # CONFIG_ECONET is not set - # CONFIG_WAN_ROUTER is not set -+# CONFIG_PHONET is not set - # CONFIG_NET_SCHED is not set - # CONFIG_DCB is not set - -@@ -341,7 +356,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic" - # CONFIG_IRDA is not set - # CONFIG_BT is not set - # CONFIG_AF_RXRPC is not set --# CONFIG_PHONET is not set - # CONFIG_WIRELESS is not set - # CONFIG_WIMAX is not set - # CONFIG_RFKILL is not set -@@ -445,7 +459,6 @@ CONFIG_MTD_PHYSMAP_OF=y - # LPDDR flash memory drivers - # - # CONFIG_MTD_LPDDR is not set --# CONFIG_MTD_QINFO_PROBE is not set - - # - # UBI - Unsorted block images -@@ -498,6 +511,7 @@ CONFIG_HAVE_IDE=y - # CONFIG_I2O is not set - # CONFIG_MACINTOSH_DRIVERS is not set - CONFIG_NETDEVICES=y -+CONFIG_COMPAT_NET_DEV_OPS=y - # CONFIG_DUMMY is not set - # CONFIG_BONDING is not set - # CONFIG_MACVLAN is not set -@@ -512,6 +526,8 @@ CONFIG_NET_ETHERNET=y - # CONFIG_SUNGEM is not set - # CONFIG_CASSINI is not set - # CONFIG_NET_VENDOR_3COM is not set -+# CONFIG_ETHOC is not set -+# CONFIG_DNET is not set - # CONFIG_NET_TULIP is not set - # CONFIG_HP100 is not set - CONFIG_IBM_NEW_EMAC=y -@@ -540,7 +556,6 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y - # - # CONFIG_WLAN_PRE80211 is not set - # CONFIG_WLAN_80211 is not set --# CONFIG_IWLWIFI_LEDS is not set - - # - # Enable WiMAX (Networking options) to see the WiMAX drivers -@@ -678,6 +693,7 @@ CONFIG_SSB_POSSIBLE=y - # CONFIG_EDAC is not set - # CONFIG_RTC_CLASS is not set - # CONFIG_DMADEVICES is not set -+# CONFIG_AUXDISPLAY is not set - # CONFIG_UIO is not set - # CONFIG_STAGING is not set - -@@ -706,6 +722,11 @@ CONFIG_INOTIFY_USER=y - # CONFIG_FUSE_FS is not set - - # -+# Caches -+# -+# CONFIG_FSCACHE is not set -+ -+# - # CD-ROM/DVD Filesystems - # - # CONFIG_ISO9660_FS is not set -@@ -749,6 +770,7 @@ CONFIG_CRAMFS=y - # CONFIG_ROMFS_FS is not set - # CONFIG_SYSV_FS is not set - # CONFIG_UFS_FS is not set -+# CONFIG_NILFS2_FS is not set - CONFIG_NETWORK_FILESYSTEMS=y - CONFIG_NFS_FS=y - CONFIG_NFS_V3=y -@@ -760,7 +782,6 @@ CONFIG_LOCKD=y - CONFIG_LOCKD_V4=y - CONFIG_NFS_COMMON=y - CONFIG_SUNRPC=y --# CONFIG_SUNRPC_REGISTER_V4 is not set - # CONFIG_RPCSEC_GSS_KRB5 is not set - # CONFIG_RPCSEC_GSS_SPKM3 is not set - # CONFIG_SMB_FS is not set -@@ -776,6 +797,7 @@ CONFIG_SUNRPC=y - CONFIG_MSDOS_PARTITION=y - # CONFIG_NLS is not set - # CONFIG_DLM is not set -+# CONFIG_BINARY_PRINTF is not set - - # - # Library routines -@@ -790,11 +812,12 @@ CONFIG_CRC32=y - # CONFIG_CRC7 is not set - # CONFIG_LIBCRC32C is not set - CONFIG_ZLIB_INFLATE=y --CONFIG_PLIST=y -+CONFIG_DECOMPRESS_GZIP=y - CONFIG_HAS_IOMEM=y - CONFIG_HAS_IOPORT=y - CONFIG_HAS_DMA=y - CONFIG_HAVE_LMB=y -+CONFIG_NLATTR=y - - # - # Kernel hacking -@@ -812,6 +835,9 @@ CONFIG_DEBUG_KERNEL=y - CONFIG_DETECT_SOFTLOCKUP=y - # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set - CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 -+CONFIG_DETECT_HUNG_TASK=y -+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set -+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 - CONFIG_SCHED_DEBUG=y - # CONFIG_SCHEDSTATS is not set - # CONFIG_TIMER_STATS is not set -@@ -841,9 +867,12 @@ CONFIG_DEBUG_BUGVERBOSE=y - # CONFIG_FAULT_INJECTION is not set - # CONFIG_LATENCYTOP is not set - CONFIG_SYSCTL_SYSCALL_CHECK=y -+# CONFIG_DEBUG_PAGEALLOC is not set - CONFIG_HAVE_FUNCTION_TRACER=y -+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y - CONFIG_HAVE_DYNAMIC_FTRACE=y - CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -+CONFIG_TRACING_SUPPORT=y - - # - # Tracers -@@ -851,17 +880,21 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y - # CONFIG_FUNCTION_TRACER is not set - # CONFIG_SCHED_TRACER is not set - # CONFIG_CONTEXT_SWITCH_TRACER is not set -+# CONFIG_EVENT_TRACER is not set - # CONFIG_BOOT_TRACER is not set - # CONFIG_TRACE_BRANCH_PROFILING is not set - # CONFIG_STACK_TRACER is not set --# CONFIG_DYNAMIC_PRINTK_DEBUG is not set -+# CONFIG_KMEMTRACE is not set -+# CONFIG_WORKQUEUE_TRACER is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_DYNAMIC_DEBUG is not set - # CONFIG_SAMPLES is not set - CONFIG_HAVE_ARCH_KGDB=y - # CONFIG_KGDB is not set - CONFIG_PRINT_STACK_DEPTH=64 - # CONFIG_DEBUG_STACKOVERFLOW is not set - # CONFIG_DEBUG_STACK_USAGE is not set --# CONFIG_DEBUG_PAGEALLOC is not set -+# CONFIG_PPC_EMULATED_STATS is not set - # CONFIG_CODE_PATCHING_SELFTEST is not set - # CONFIG_FTR_FIXUP_SELFTEST is not set - # CONFIG_MSI_BITMAP_SELFTEST is not set -@@ -892,10 +925,12 @@ CONFIG_CRYPTO_BLKCIPHER2=y - CONFIG_CRYPTO_HASH=y - CONFIG_CRYPTO_HASH2=y - CONFIG_CRYPTO_RNG2=y -+CONFIG_CRYPTO_PCOMP=y - CONFIG_CRYPTO_MANAGER=y - CONFIG_CRYPTO_MANAGER2=y - # CONFIG_CRYPTO_GF128MUL is not set - # CONFIG_CRYPTO_NULL is not set -+CONFIG_CRYPTO_WORKQUEUE=y - # CONFIG_CRYPTO_CRYPTD is not set - # CONFIG_CRYPTO_AUTHENC is not set - # CONFIG_CRYPTO_TEST is not set -@@ -964,6 +999,7 @@ CONFIG_CRYPTO_DES=y - # Compression - # - # CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_ZLIB is not set - # CONFIG_CRYPTO_LZO is not set - - # -@@ -972,5 +1008,6 @@ CONFIG_CRYPTO_DES=y - # CONFIG_CRYPTO_ANSI_CPRNG is not set - CONFIG_CRYPTO_HW=y - # CONFIG_CRYPTO_DEV_HIFN_795X is not set -+# CONFIG_CRYPTO_DEV_PPC4XX is not set - # CONFIG_PPC_CLOCK is not set - # CONFIG_VIRTUALIZATION is not set ---- a/arch/powerpc/platforms/40x/Kconfig -+++ b/arch/powerpc/platforms/40x/Kconfig -@@ -56,6 +56,7 @@ config MAKALU - select 405EX - select PCI - select PPC4xx_PCI_EXPRESS -+ select PPC40x_SIMPLE - help - This option enables support for the AMCC PPC405EX board. - ---- a/arch/powerpc/platforms/40x/Makefile -+++ b/arch/powerpc/platforms/40x/Makefile -@@ -1,6 +1,5 @@ - obj-$(CONFIG_KILAUEA) += kilauea.o - obj-$(CONFIG_HCU4) += hcu4.o --obj-$(CONFIG_MAKALU) += makalu.o - obj-$(CONFIG_WALNUT) += walnut.o - obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o - obj-$(CONFIG_EP405) += ep405.o ---- a/arch/powerpc/platforms/40x/makalu.c -+++ /dev/null -@@ -1,60 +0,0 @@ --/* -- * Makalu board specific routines -- * -- * Copyright 2007 DENX Software Engineering, Stefan Roese -- * -- * Based on the Walnut code by -- * Josh Boyer -- * Copyright 2007 IBM Corporation -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License as published by the -- * Free Software Foundation; either version 2 of the License, or (at your -- * option) any later version. -- */ --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --static __initdata struct of_device_id makalu_of_bus[] = { -- { .compatible = "ibm,plb4", }, -- { .compatible = "ibm,opb", }, -- { .compatible = "ibm,ebc", }, -- {}, --}; -- --static int __init makalu_device_probe(void) --{ -- of_platform_bus_probe(NULL, makalu_of_bus, NULL); -- -- return 0; --} --machine_device_initcall(makalu, makalu_device_probe); -- --static int __init makalu_probe(void) --{ -- unsigned long root = of_get_flat_dt_root(); -- -- if (!of_flat_dt_is_compatible(root, "amcc,makalu")) -- return 0; -- -- ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; -- -- return 1; --} -- --define_machine(makalu) { -- .name = "Makalu", -- .probe = makalu_probe, -- .progress = udbg_progress, -- .init_IRQ = uic_init_tree, -- .get_irq = uic_get_irq, -- .restart = ppc4xx_reset_system, -- .calibrate_decr = generic_calibrate_decr, --}; ---- a/arch/powerpc/platforms/40x/ppc40x_simple.c -+++ b/arch/powerpc/platforms/40x/ppc40x_simple.c -@@ -51,7 +51,8 @@ machine_device_initcall(ppc40x_simple, p - * board.c file for it rather than adding it to this list. - */ - static char *board[] __initdata = { -- "amcc,acadia" -+ "amcc,acadia", -+ "amcc,makalu" - }; - - static int __init ppc40x_probe(void) diff --git a/target/linux/ppc40x/patches/002-kilauea_halekala_ppc40x_simple.patch b/target/linux/ppc40x/patches/002-kilauea_halekala_ppc40x_simple.patch deleted file mode 100644 index 0b17e1b81..000000000 --- a/target/linux/ppc40x/patches/002-kilauea_halekala_ppc40x_simple.patch +++ /dev/null @@ -1,440 +0,0 @@ ---- a/arch/powerpc/configs/40x/kilauea_defconfig -+++ b/arch/powerpc/configs/40x/kilauea_defconfig -@@ -1,7 +1,7 @@ - # - # Automatically generated make config: don't edit --# Linux kernel version: 2.6.29-rc2 --# Tue Jan 20 08:17:52 2009 -+# Linux kernel version: 2.6.30-rc7 -+# Wed Jun 3 10:18:16 2009 - # - # CONFIG_PPC64 is not set - -@@ -27,6 +27,7 @@ CONFIG_GENERIC_TIME=y - CONFIG_GENERIC_TIME_VSYSCALL=y - CONFIG_GENERIC_CLOCKEVENTS=y - CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y - # CONFIG_HAVE_SETUP_PER_CPU_AREA is not set - CONFIG_IRQ_PER_CPU=y - CONFIG_STACKTRACE_SUPPORT=y -@@ -49,10 +50,12 @@ CONFIG_PPC_UDBG_16550=y - # CONFIG_GENERIC_TBSYNC is not set - CONFIG_AUDIT_ARCH=y - CONFIG_GENERIC_BUG=y -+CONFIG_DTC=y - # CONFIG_DEFAULT_UIMAGE is not set - CONFIG_PPC_DCR_NATIVE=y - # CONFIG_PPC_DCR_MMIO is not set - CONFIG_PPC_DCR=y -+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y - CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - - # -@@ -67,9 +70,19 @@ CONFIG_SWAP=y - CONFIG_SYSVIPC=y - CONFIG_SYSVIPC_SYSCTL=y - CONFIG_POSIX_MQUEUE=y -+CONFIG_POSIX_MQUEUE_SYSCTL=y - # CONFIG_BSD_PROCESS_ACCT is not set - # CONFIG_TASKSTATS is not set - # CONFIG_AUDIT is not set -+ -+# -+# RCU Subsystem -+# -+CONFIG_CLASSIC_RCU=y -+# CONFIG_TREE_RCU is not set -+# CONFIG_PREEMPT_RCU is not set -+# CONFIG_TREE_RCU_TRACE is not set -+# CONFIG_PREEMPT_RCU_TRACE is not set - # CONFIG_IKCONFIG is not set - CONFIG_LOG_BUF_SHIFT=14 - CONFIG_GROUP_SCHED=y -@@ -84,22 +97,24 @@ CONFIG_SYSFS_DEPRECATED_V2=y - # CONFIG_NAMESPACES is not set - CONFIG_BLK_DEV_INITRD=y - CONFIG_INITRAMFS_SOURCE="" -+CONFIG_RD_GZIP=y -+# CONFIG_RD_BZIP2 is not set -+# CONFIG_RD_LZMA is not set - # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set - CONFIG_SYSCTL=y -+CONFIG_ANON_INODES=y - CONFIG_EMBEDDED=y - CONFIG_SYSCTL_SYSCALL=y - CONFIG_KALLSYMS=y - CONFIG_KALLSYMS_ALL=y --CONFIG_KALLSYMS_STRIP_GENERATED=y - CONFIG_KALLSYMS_EXTRA_PASS=y -+# CONFIG_STRIP_ASM_SYMS is not set - CONFIG_HOTPLUG=y - CONFIG_PRINTK=y - CONFIG_BUG=y - CONFIG_ELF_CORE=y --CONFIG_COMPAT_BRK=y - CONFIG_BASE_FULL=y - CONFIG_FUTEX=y --CONFIG_ANON_INODES=y - CONFIG_EPOLL=y - CONFIG_SIGNALFD=y - CONFIG_TIMERFD=y -@@ -109,10 +124,12 @@ CONFIG_AIO=y - CONFIG_VM_EVENT_COUNTERS=y - CONFIG_PCI_QUIRKS=y - CONFIG_SLUB_DEBUG=y -+CONFIG_COMPAT_BRK=y - # CONFIG_SLAB is not set - CONFIG_SLUB=y - # CONFIG_SLOB is not set - # CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set - CONFIG_HAVE_OPROFILE=y - # CONFIG_KPROBES is not set - CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -@@ -120,6 +137,7 @@ CONFIG_HAVE_IOREMAP_PROT=y - CONFIG_HAVE_KPROBES=y - CONFIG_HAVE_KRETPROBES=y - CONFIG_HAVE_ARCH_TRACEHOOK=y -+# CONFIG_SLOW_WORK is not set - # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set - CONFIG_SLABINFO=y - CONFIG_RT_MUTEXES=y -@@ -132,7 +150,6 @@ CONFIG_MODULE_UNLOAD=y - # CONFIG_MODULE_SRCVERSION_ALL is not set - CONFIG_BLOCK=y - CONFIG_LBD=y --# CONFIG_BLK_DEV_IO_TRACE is not set - # CONFIG_BLK_DEV_BSG is not set - # CONFIG_BLK_DEV_INTEGRITY is not set - -@@ -148,11 +165,6 @@ CONFIG_DEFAULT_AS=y - # CONFIG_DEFAULT_CFQ is not set - # CONFIG_DEFAULT_NOOP is not set - CONFIG_DEFAULT_IOSCHED="anticipatory" --CONFIG_CLASSIC_RCU=y --# CONFIG_TREE_RCU is not set --# CONFIG_PREEMPT_RCU is not set --# CONFIG_TREE_RCU_TRACE is not set --# CONFIG_PREEMPT_RCU_TRACE is not set - # CONFIG_FREEZER is not set - CONFIG_PPC4xx_PCI_EXPRESS=y - -@@ -170,7 +182,7 @@ CONFIG_KILAUEA=y - # CONFIG_MAKALU is not set - # CONFIG_WALNUT is not set - # CONFIG_XILINX_VIRTEX_GENERIC_BOARD is not set --# CONFIG_PPC40x_SIMPLE is not set -+CONFIG_PPC40x_SIMPLE=y - CONFIG_405EX=y - # CONFIG_IPIC is not set - # CONFIG_MPIC is not set -@@ -228,9 +240,12 @@ CONFIG_ZONE_DMA_FLAG=1 - CONFIG_BOUNCE=y - CONFIG_VIRT_TO_BUS=y - CONFIG_UNEVICTABLE_LRU=y -+CONFIG_HAVE_MLOCK=y -+CONFIG_HAVE_MLOCKED_PAGE_BIT=y - CONFIG_PPC_4K_PAGES=y - # CONFIG_PPC_16K_PAGES is not set - # CONFIG_PPC_64K_PAGES is not set -+# CONFIG_PPC_256K_PAGES is not set - CONFIG_FORCE_MAX_ZONEORDER=11 - CONFIG_PROC_DEVICETREE=y - # CONFIG_CMDLINE_BOOL is not set -@@ -255,6 +270,7 @@ CONFIG_ARCH_SUPPORTS_MSI=y - CONFIG_PCI_LEGACY=y - # CONFIG_PCI_DEBUG is not set - # CONFIG_PCI_STUB is not set -+# CONFIG_PCI_IOV is not set - # CONFIG_PCCARD is not set - # CONFIG_HOTPLUG_PCI is not set - # CONFIG_HAS_RAPIDIO is not set -@@ -272,14 +288,12 @@ CONFIG_PAGE_OFFSET=0xc0000000 - CONFIG_KERNEL_START=0xc0000000 - CONFIG_PHYSICAL_START=0x00000000 - CONFIG_TASK_SIZE=0xc0000000 --CONFIG_CONSISTENT_START=0xff100000 - CONFIG_CONSISTENT_SIZE=0x00200000 - CONFIG_NET=y - - # - # Networking options - # --CONFIG_COMPAT_NET_DEV_OPS=y - CONFIG_PACKET=y - # CONFIG_PACKET_MMAP is not set - CONFIG_UNIX=y -@@ -329,6 +343,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" - # CONFIG_LAPB is not set - # CONFIG_ECONET is not set - # CONFIG_WAN_ROUTER is not set -+# CONFIG_PHONET is not set - # CONFIG_NET_SCHED is not set - # CONFIG_DCB is not set - -@@ -341,7 +356,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic" - # CONFIG_IRDA is not set - # CONFIG_BT is not set - # CONFIG_AF_RXRPC is not set --# CONFIG_PHONET is not set - # CONFIG_WIRELESS is not set - # CONFIG_WIMAX is not set - # CONFIG_RFKILL is not set -@@ -445,7 +459,6 @@ CONFIG_MTD_PHYSMAP_OF=y - # LPDDR flash memory drivers - # - # CONFIG_MTD_LPDDR is not set --# CONFIG_MTD_QINFO_PROBE is not set - - # - # UBI - Unsorted block images -@@ -498,6 +511,7 @@ CONFIG_HAVE_IDE=y - # CONFIG_I2O is not set - # CONFIG_MACINTOSH_DRIVERS is not set - CONFIG_NETDEVICES=y -+CONFIG_COMPAT_NET_DEV_OPS=y - # CONFIG_DUMMY is not set - # CONFIG_BONDING is not set - # CONFIG_MACVLAN is not set -@@ -512,6 +526,8 @@ CONFIG_NET_ETHERNET=y - # CONFIG_SUNGEM is not set - # CONFIG_CASSINI is not set - # CONFIG_NET_VENDOR_3COM is not set -+# CONFIG_ETHOC is not set -+# CONFIG_DNET is not set - # CONFIG_NET_TULIP is not set - # CONFIG_HP100 is not set - CONFIG_IBM_NEW_EMAC=y -@@ -540,7 +556,6 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y - # - # CONFIG_WLAN_PRE80211 is not set - # CONFIG_WLAN_80211 is not set --# CONFIG_IWLWIFI_LEDS is not set - - # - # Enable WiMAX (Networking options) to see the WiMAX drivers -@@ -678,6 +693,7 @@ CONFIG_SSB_POSSIBLE=y - # CONFIG_EDAC is not set - # CONFIG_RTC_CLASS is not set - # CONFIG_DMADEVICES is not set -+# CONFIG_AUXDISPLAY is not set - # CONFIG_UIO is not set - # CONFIG_STAGING is not set - -@@ -706,6 +722,11 @@ CONFIG_INOTIFY_USER=y - # CONFIG_FUSE_FS is not set - - # -+# Caches -+# -+# CONFIG_FSCACHE is not set -+ -+# - # CD-ROM/DVD Filesystems - # - # CONFIG_ISO9660_FS is not set -@@ -749,6 +770,7 @@ CONFIG_CRAMFS=y - # CONFIG_ROMFS_FS is not set - # CONFIG_SYSV_FS is not set - # CONFIG_UFS_FS is not set -+# CONFIG_NILFS2_FS is not set - CONFIG_NETWORK_FILESYSTEMS=y - CONFIG_NFS_FS=y - CONFIG_NFS_V3=y -@@ -760,7 +782,6 @@ CONFIG_LOCKD=y - CONFIG_LOCKD_V4=y - CONFIG_NFS_COMMON=y - CONFIG_SUNRPC=y --# CONFIG_SUNRPC_REGISTER_V4 is not set - # CONFIG_RPCSEC_GSS_KRB5 is not set - # CONFIG_RPCSEC_GSS_SPKM3 is not set - # CONFIG_SMB_FS is not set -@@ -776,6 +797,7 @@ CONFIG_SUNRPC=y - CONFIG_MSDOS_PARTITION=y - # CONFIG_NLS is not set - # CONFIG_DLM is not set -+# CONFIG_BINARY_PRINTF is not set - - # - # Library routines -@@ -790,11 +812,12 @@ CONFIG_CRC32=y - # CONFIG_CRC7 is not set - # CONFIG_LIBCRC32C is not set - CONFIG_ZLIB_INFLATE=y --CONFIG_PLIST=y -+CONFIG_DECOMPRESS_GZIP=y - CONFIG_HAS_IOMEM=y - CONFIG_HAS_IOPORT=y - CONFIG_HAS_DMA=y - CONFIG_HAVE_LMB=y -+CONFIG_NLATTR=y - - # - # Kernel hacking -@@ -812,6 +835,9 @@ CONFIG_DEBUG_KERNEL=y - CONFIG_DETECT_SOFTLOCKUP=y - # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set - CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 -+CONFIG_DETECT_HUNG_TASK=y -+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set -+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 - CONFIG_SCHED_DEBUG=y - # CONFIG_SCHEDSTATS is not set - # CONFIG_TIMER_STATS is not set -@@ -841,9 +867,12 @@ CONFIG_DEBUG_BUGVERBOSE=y - # CONFIG_FAULT_INJECTION is not set - # CONFIG_LATENCYTOP is not set - CONFIG_SYSCTL_SYSCALL_CHECK=y -+# CONFIG_DEBUG_PAGEALLOC is not set - CONFIG_HAVE_FUNCTION_TRACER=y -+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y - CONFIG_HAVE_DYNAMIC_FTRACE=y - CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -+CONFIG_TRACING_SUPPORT=y - - # - # Tracers -@@ -851,17 +880,21 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y - # CONFIG_FUNCTION_TRACER is not set - # CONFIG_SCHED_TRACER is not set - # CONFIG_CONTEXT_SWITCH_TRACER is not set -+# CONFIG_EVENT_TRACER is not set - # CONFIG_BOOT_TRACER is not set - # CONFIG_TRACE_BRANCH_PROFILING is not set - # CONFIG_STACK_TRACER is not set --# CONFIG_DYNAMIC_PRINTK_DEBUG is not set -+# CONFIG_KMEMTRACE is not set -+# CONFIG_WORKQUEUE_TRACER is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_DYNAMIC_DEBUG is not set - # CONFIG_SAMPLES is not set - CONFIG_HAVE_ARCH_KGDB=y - # CONFIG_KGDB is not set - CONFIG_PRINT_STACK_DEPTH=64 - # CONFIG_DEBUG_STACKOVERFLOW is not set - # CONFIG_DEBUG_STACK_USAGE is not set --# CONFIG_DEBUG_PAGEALLOC is not set -+# CONFIG_PPC_EMULATED_STATS is not set - # CONFIG_CODE_PATCHING_SELFTEST is not set - # CONFIG_FTR_FIXUP_SELFTEST is not set - # CONFIG_MSI_BITMAP_SELFTEST is not set -@@ -892,10 +925,12 @@ CONFIG_CRYPTO_BLKCIPHER2=y - CONFIG_CRYPTO_HASH=y - CONFIG_CRYPTO_HASH2=y - CONFIG_CRYPTO_RNG2=y -+CONFIG_CRYPTO_PCOMP=y - CONFIG_CRYPTO_MANAGER=y - CONFIG_CRYPTO_MANAGER2=y - # CONFIG_CRYPTO_GF128MUL is not set - # CONFIG_CRYPTO_NULL is not set -+CONFIG_CRYPTO_WORKQUEUE=y - # CONFIG_CRYPTO_CRYPTD is not set - # CONFIG_CRYPTO_AUTHENC is not set - # CONFIG_CRYPTO_TEST is not set -@@ -964,6 +999,7 @@ CONFIG_CRYPTO_DES=y - # Compression - # - # CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_ZLIB is not set - # CONFIG_CRYPTO_LZO is not set - - # -@@ -972,5 +1008,6 @@ CONFIG_CRYPTO_DES=y - # CONFIG_CRYPTO_ANSI_CPRNG is not set - CONFIG_CRYPTO_HW=y - # CONFIG_CRYPTO_DEV_HIFN_795X is not set -+# CONFIG_CRYPTO_DEV_PPC4XX is not set - # CONFIG_PPC_CLOCK is not set - # CONFIG_VIRTUALIZATION is not set ---- a/arch/powerpc/platforms/40x/Kconfig -+++ b/arch/powerpc/platforms/40x/Kconfig -@@ -45,6 +45,7 @@ config KILAUEA - depends on 40x - default n - select 405EX -+ select PPC40x_SIMPLE - select PPC4xx_PCI_EXPRESS - help - This option enables support for the AMCC PPC405EX evaluation board. ---- a/arch/powerpc/platforms/40x/Makefile -+++ b/arch/powerpc/platforms/40x/Makefile -@@ -1,4 +1,3 @@ --obj-$(CONFIG_KILAUEA) += kilauea.o - obj-$(CONFIG_HCU4) += hcu4.o - obj-$(CONFIG_WALNUT) += walnut.o - obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o ---- a/arch/powerpc/platforms/40x/kilauea.c -+++ /dev/null -@@ -1,60 +0,0 @@ --/* -- * Kilauea board specific routines -- * -- * Copyright 2007-2008 DENX Software Engineering, Stefan Roese -- * -- * Based on the Walnut code by -- * Josh Boyer -- * Copyright 2007 IBM Corporation -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License as published by the -- * Free Software Foundation; either version 2 of the License, or (at your -- * option) any later version. -- */ --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --static __initdata struct of_device_id kilauea_of_bus[] = { -- { .compatible = "ibm,plb4", }, -- { .compatible = "ibm,opb", }, -- { .compatible = "ibm,ebc", }, -- {}, --}; -- --static int __init kilauea_device_probe(void) --{ -- of_platform_bus_probe(NULL, kilauea_of_bus, NULL); -- -- return 0; --} --machine_device_initcall(kilauea, kilauea_device_probe); -- --static int __init kilauea_probe(void) --{ -- unsigned long root = of_get_flat_dt_root(); -- -- if (!of_flat_dt_is_compatible(root, "amcc,kilauea")) -- return 0; -- -- ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); -- -- return 1; --} -- --define_machine(kilauea) { -- .name = "Kilauea", -- .probe = kilauea_probe, -- .progress = udbg_progress, -- .init_IRQ = uic_init_tree, -- .get_irq = uic_get_irq, -- .restart = ppc4xx_reset_system, -- .calibrate_decr = generic_calibrate_decr, --}; ---- a/arch/powerpc/platforms/40x/ppc40x_simple.c -+++ b/arch/powerpc/platforms/40x/ppc40x_simple.c -@@ -52,6 +52,8 @@ machine_device_initcall(ppc40x_simple, p - */ - static char *board[] __initdata = { - "amcc,acadia", -+ "amcc,haleakala", -+ "amcc,kilauea", - "amcc,makalu" - }; - diff --git a/target/linux/ppc40x/patches/004-magicbox.patch b/target/linux/ppc40x/patches/004-magicbox.patch index d6ce22d4a..95736a1e0 100644 --- a/target/linux/ppc40x/patches/004-magicbox.patch +++ b/target/linux/ppc40x/patches/004-magicbox.patch @@ -377,7 +377,7 @@ +}; --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile -@@ -42,6 +42,7 @@ $(obj)/ebony.o: BOOTCFLAGS += -mcpu=440 +@@ -43,6 +43,7 @@ $(obj)/cuboot-hotfoot.o: BOOTCFLAGS += - $(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440 $(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440 $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405 @@ -385,17 +385,18 @@ $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405 $(obj)/virtex405-head.o: BOOTAFLAGS += -mcpu=405 -@@ -75,7 +76,7 @@ src-plat := of.c cuboot-52xx.c cuboot-82 +@@ -76,7 +77,8 @@ src-plat := of.c cuboot-52xx.c cuboot-82 cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \ cuboot-warp.c cuboot-85xx-cpm2.c cuboot-yosemite.c simpleboot.c \ virtex405-head.S virtex.c redboot-83xx.c cuboot-sam440ep.c \ -- cuboot-acadia.c cuboot-amigaone.c -+ cuboot-acadia.c cuboot-amigaone.c cuboot-magicbox.c +- cuboot-acadia.c cuboot-amigaone.c cuboot-kilauea.c ++ cuboot-acadia.c cuboot-amigaone.c cuboot-kilauea.c \ ++ cuboot-magicbox.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) -@@ -192,6 +193,7 @@ image-$(CONFIG_DEFAULT_UIMAGE) += uImag - image-$(CONFIG_EP405) += dtbImage.ep405 +@@ -194,6 +196,7 @@ image-$(CONFIG_EP405) += dtbImage.ep40 + image-$(CONFIG_HOTFOOT) += cuImage.hotfoot image-$(CONFIG_WALNUT) += treeImage.walnut image-$(CONFIG_ACADIA) += cuImage.acadia +image-$(CONFIG_MAGICBOX) += cuImage.magicbox @@ -404,7 +405,7 @@ image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig -@@ -50,6 +50,16 @@ config KILAUEA +@@ -60,6 +60,16 @@ config KILAUEA help This option enables support for the AMCC PPC405EX evaluation board. @@ -423,12 +424,12 @@ depends on 40x --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c -@@ -54,7 +54,8 @@ static char *board[] __initdata = { - "amcc,acadia", +@@ -55,7 +55,8 @@ static char *board[] __initdata = { "amcc,haleakala", "amcc,kilauea", -- "amcc,makalu" -+ "amcc,makalu", + "amcc,makalu", +- "est,hotfoot" ++ "est,hotfoot", + "magicbox" }; diff --git a/target/linux/ppc40x/patches/005-openrb.patch b/target/linux/ppc40x/patches/005-openrb.patch index 43407c202..b6dff6eba 100644 --- a/target/linux/ppc40x/patches/005-openrb.patch +++ b/target/linux/ppc40x/patches/005-openrb.patch @@ -353,7 +353,7 @@ +}; --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile -@@ -43,6 +43,7 @@ $(obj)/cuboot-taishan.o: BOOTCFLAGS += - +@@ -44,6 +44,7 @@ $(obj)/cuboot-taishan.o: BOOTCFLAGS += - $(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440 $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405 $(obj)/cuboot-magicbox.o: BOOTCFLAGS += -mcpu=405 @@ -361,17 +361,16 @@ $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405 $(obj)/virtex405-head.o: BOOTAFLAGS += -mcpu=405 -@@ -76,7 +77,8 @@ src-plat := of.c cuboot-52xx.c cuboot-82 - cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \ +@@ -78,7 +79,7 @@ src-plat := of.c cuboot-52xx.c cuboot-82 cuboot-warp.c cuboot-85xx-cpm2.c cuboot-yosemite.c simpleboot.c \ virtex405-head.S virtex.c redboot-83xx.c cuboot-sam440ep.c \ -- cuboot-acadia.c cuboot-amigaone.c cuboot-magicbox.c -+ cuboot-acadia.c cuboot-amigaone.c cuboot-magicbox.c \ -+ cuboot-openrb.c + cuboot-acadia.c cuboot-amigaone.c cuboot-kilauea.c \ +- cuboot-magicbox.c ++ cuboot-magicbox.c cuboot-openrb.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) -@@ -194,6 +196,7 @@ image-$(CONFIG_EP405) += dtbImage.ep40 +@@ -197,6 +198,7 @@ image-$(CONFIG_HOTFOOT) += cuImage.hot image-$(CONFIG_WALNUT) += treeImage.walnut image-$(CONFIG_ACADIA) += cuImage.acadia image-$(CONFIG_MAGICBOX) += cuImage.magicbox @@ -381,7 +380,7 @@ image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig -@@ -60,6 +60,16 @@ config MAGICBOX +@@ -70,6 +70,16 @@ config MAGICBOX help This option enables support for the Magicbox boards. @@ -400,10 +399,10 @@ depends on 40x --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c -@@ -55,7 +55,8 @@ static char *board[] __initdata = { - "amcc,haleakala", +@@ -56,7 +56,8 @@ static char *board[] __initdata = { "amcc,kilauea", "amcc,makalu", + "est,hotfoot", - "magicbox" + "magicbox", + "openrb" diff --git a/target/linux/ppc40x/patches/101-pata-magicbox-cf-driver.patch b/target/linux/ppc40x/patches/101-pata-magicbox-cf-driver.patch index f738f8968..389358777 100644 --- a/target/linux/ppc40x/patches/101-pata-magicbox-cf-driver.patch +++ b/target/linux/ppc40x/patches/101-pata-magicbox-cf-driver.patch @@ -1,6 +1,6 @@ --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig -@@ -698,6 +698,16 @@ config PATA_IXP4XX_CF +@@ -745,6 +745,16 @@ config PATA_IXP4XX_CF If unsure, say N. @@ -19,14 +19,14 @@ depends on CPU_CAVIUM_OCTEON --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile -@@ -48,6 +48,7 @@ obj-$(CONFIG_PATA_OPTI) += pata_opti.o +@@ -49,6 +49,7 @@ obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o +obj-$(CONFIG_PATA_MAGICBOX_CF) += pata_magicbox_cf.o obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o - obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o + obj-$(CONFIG_PATA_PALMLD) += pata_palmld.o --- /dev/null +++ b/drivers/ata/pata_magicbox_cf.c @@ -0,0 +1,404 @@ diff --git a/target/linux/ppc40x/patches/110-kilauea_openwrt_flashmap.patch b/target/linux/ppc40x/patches/110-kilauea_openwrt_flashmap.patch index 3244e2c93..5e5cc5298 100644 --- a/target/linux/ppc40x/patches/110-kilauea_openwrt_flashmap.patch +++ b/target/linux/ppc40x/patches/110-kilauea_openwrt_flashmap.patch @@ -1,23 +1,15 @@ --- a/arch/powerpc/boot/dts/kilauea.dts +++ b/arch/powerpc/boot/dts/kilauea.dts -@@ -150,15 +150,15 @@ - #size-cells = <1>; - partition@0 { - label = "kernel"; -- reg = <0x00000000 0x00200000>; -+ reg = <0x00000000 0x001e0000>; +@@ -157,12 +157,8 @@ + reg = <0x001e0000 0x00020000>; }; -- partition@200000 { + partition@200000 { - label = "root"; - reg = <0x00200000 0x00200000>; -+ partition@1e0000 { -+ label = "device-tree"; -+ reg = <0x001e0000 0x0020000>; - }; +- }; - partition@400000 { - label = "user"; - reg = <0x00400000 0x03b60000>; -+ partition@200000 { + label = "rootfs"; + reg = <0x00200000 0x03d60000>; }; diff --git a/target/linux/ppc40x/patches/900-backport-fix-annotation-of-pcibios_claim_one_bus.patch b/target/linux/ppc40x/patches/900-backport-fix-annotation-of-pcibios_claim_one_bus.patch deleted file mode 100644 index 01a70c52c..000000000 --- a/target/linux/ppc40x/patches/900-backport-fix-annotation-of-pcibios_claim_one_bus.patch +++ /dev/null @@ -1,42 +0,0 @@ -From: Stephen Rothwell -Date: Mon, 1 Jun 2009 14:53:53 +0000 (+0000) -Subject: powerpc/pci: Fix annotation of pcibios_claim_one_bus -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fbenh%2Fpowerpc.git;a=commitdiff_plain;h=baf75b0a42a1b3f6fca80f8949b6141eaff61b0d - -powerpc/pci: Fix annotation of pcibios_claim_one_bus - -It was __devinit, but it is also within a CONFIG_HOTPLUG guarded section -of code, so the __devinit does nothing but cause the following warning: - -WARNING: vmlinux.o(.text+0x107a8): Section mismatch in reference from the function pcibios_finish_adding_to_bus() to the function .devinit.text:pcibios_claim_one_bus() -The function pcibios_finish_adding_to_bus() references -the function __devinit pcibios_claim_one_bus(). -This is often because pcibios_finish_adding_to_bus lacks a __devinit -annotation or the annotation of pcibios_claim_one_bus is wrong. - -It is also only (externally) used in arch/powerpc/kernel/of_platform.c -which cannot be built as a module so don't export it. - -Signed-off-by: Stephen Rothwell -Signed-off-by: Benjamin Herrenschmidt ---- - ---- a/arch/powerpc/kernel/pci-common.c -+++ b/arch/powerpc/kernel/pci-common.c -@@ -1505,7 +1505,7 @@ void __init pcibios_resource_survey(void - * rest of the code later, for now, keep it as-is as our main - * resource allocation function doesn't deal with sub-trees yet. - */ --void __devinit pcibios_claim_one_bus(struct pci_bus *bus) -+void pcibios_claim_one_bus(struct pci_bus *bus) - { - struct pci_dev *dev; - struct pci_bus *child_bus; -@@ -1533,7 +1533,6 @@ void __devinit pcibios_claim_one_bus(str - list_for_each_entry(child_bus, &bus->children, node) - pcibios_claim_one_bus(child_bus); - } --EXPORT_SYMBOL_GPL(pcibios_claim_one_bus); - - - /* pcibios_finish_adding_to_bus diff --git a/target/linux/ppc44x/Makefile b/target/linux/ppc44x/Makefile index 5b536adaf..8ba42d80e 100644 --- a/target/linux/ppc44x/Makefile +++ b/target/linux/ppc44x/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2007-2009 OpenWrt.org +# Copyright (C) 2007-2010 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -12,7 +12,7 @@ BOARDNAME:=AMCC/IBM PPC44x FEATURES:=squashfs CFLAGS:=-Os -pipe -funit-at-a-time -mcpu=440 -LINUX_VERSION:=2.6.30.10 +LINUX_VERSION:=2.6.32.8 include $(INCLUDE_DIR)/target.mk diff --git a/target/linux/ppc44x/config-default b/target/linux/ppc44x/config-default index 313fd3c7f..4a0b3e34a 100644 --- a/target/linux/ppc44x/config-default +++ b/target/linux/ppc44x/config-default @@ -37,6 +37,7 @@ CONFIG_DEVPORT=y # CONFIG_E200 is not set CONFIG_EARLY_PRINTK=y # CONFIG_EBONY is not set +# CONFIG_EIGER is not set CONFIG_EXTRA_TARGETS="uImage" CONFIG_FORCE_MAX_ZONEORDER=11 # CONFIG_FSL_ULI1575 is not set @@ -128,6 +129,7 @@ CONFIG_PPC4xx_PCI_EXPRESS=y # CONFIG_PPC_85xx is not set # CONFIG_PPC_8xx is not set # CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_BOOK3S_32 is not set # CONFIG_PPC_CELL is not set # CONFIG_PPC_CELL_NATIVE is not set # CONFIG_PPC_CLOCK is not set @@ -164,6 +166,7 @@ CONFIG_SERIAL_8250_EXTENDED=y # CONFIG_SERIAL_8250_RSA is not set CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SWIOTLB=y CONFIG_TAISHAN=y CONFIG_TASK_SIZE=0xc0000000 CONFIG_USB_EHCI_HCD_PPC_OF=y diff --git a/target/linux/ppc44x/patches/005-canyonlands_remove_nonexisting_uarts.patch b/target/linux/ppc44x/patches/005-canyonlands_remove_nonexisting_uarts.patch index b98b36712..5a240de9e 100644 --- a/target/linux/ppc44x/patches/005-canyonlands_remove_nonexisting_uarts.patch +++ b/target/linux/ppc44x/patches/005-canyonlands_remove_nonexisting_uarts.patch @@ -1,6 +1,6 @@ --- a/arch/powerpc/boot/dts/canyonlands.dts +++ b/arch/powerpc/boot/dts/canyonlands.dts -@@ -239,28 +239,6 @@ +@@ -262,28 +262,6 @@ interrupts = <0x1 0x4>; }; diff --git a/target/linux/rdc/config-2.6.32 b/target/linux/rdc/config-2.6.32 new file mode 100644 index 000000000..b96fca3ed --- /dev/null +++ b/target/linux/rdc/config-2.6.32 @@ -0,0 +1,288 @@ +# CONFIG_4KSTACKS is not set +# CONFIG_60XX_WDT is not set +# CONFIG_64BIT is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM1535_WDT is not set +CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig" +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_DEFAULT_IDLE=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +# CONFIG_ARCH_SUPPORTS_MSI is not set +CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +# CONFIG_ARPD is not set +# CONFIG_AUDIT_ARCH is not set +# CONFIG_BASE_FULL is not set +CONFIG_BASE_SMALL=1 +CONFIG_BITREVERSE=y +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BOUNCE=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CFG80211_DEFAULT_PS_VALUE=0 +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_CMDLINE="console=ttyS0,38400 rootfstype=squashfs,jffs2" +CONFIG_CMDLINE_BOOL=y +# CONFIG_CMDLINE_OVERRIDE is not set +# CONFIG_COMPAT_VDSO is not set +# CONFIG_CPU5_WDT is not set +# CONFIG_CPU_SUP_AMD is not set +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_CYRIX_32 is not set +# CONFIG_CPU_SUP_INTEL is not set +# CONFIG_CPU_SUP_TRANSMETA_32 is not set +# CONFIG_CPU_SUP_UMC_32 is not set +# CONFIG_CS5535_GPIO is not set +# CONFIG_DCDBAS is not set +# CONFIG_DEBUG_FS is not set +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DEFAULT_IO_DELAY_TYPE=0 +# CONFIG_DELL_RBU is not set +CONFIG_DEVPORT=y +# CONFIG_DMI is not set +CONFIG_DOUBLEFAULT=y +# CONFIG_EARLY_PRINTK is not set +# CONFIG_EDD is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_FIRMWARE_MEMMAP is not set +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FRAME_POINTER is not set +# CONFIG_FSNOTIFY is not set +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +# CONFIG_GENERIC_CPU is not set +CONFIG_GENERIC_FIND_FIRST_BIT=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_GENERIC_TIME_VSYSCALL is not set +# CONFIG_GEN_RTC is not set +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +# CONFIG_HAMRADIO is not set +# CONFIG_HANGCHECK_TIMER is not set +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_AOUT=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_KMEMCHECK=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ATOMIC_IOMAP=y +# CONFIG_HAVE_CPUMASK_OF_CPU_MAP is not set +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_KVM=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y +# CONFIG_HIGHMEM4G is not set +# CONFIG_HIGHMEM64G is not set +# CONFIG_HIGH_RES_TIMERS is not set +# CONFIG_HPET_TIMER is not set +# CONFIG_HP_WATCHDOG is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HW_RANDOM is not set +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I8K is not set +# CONFIG_IB700_WDT is not set +# CONFIG_IBMASR is not set +# CONFIG_IOMMU_API is not set +# CONFIG_IOMMU_HELPER is not set +# CONFIG_IOMMU_STRESS is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ISA is not set +CONFIG_ISA_DMA_API=y +# CONFIG_ISCSI_IBFT_FIND is not set +# CONFIG_IT8712F_WDT is not set +# CONFIG_IT87_WDT is not set +# CONFIG_ITCO_WDT is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_KTIME_SCALAR=y +# CONFIG_LEDS_ALIX2 is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_M386 is not set +CONFIG_M486=y +# CONFIG_M586 is not set +# CONFIG_M586MMX is not set +# CONFIG_M586TSC is not set +# CONFIG_M686 is not set +# CONFIG_MACHZ_WDT is not set +CONFIG_MATH_EMULATION=y +# CONFIG_MATOM is not set +# CONFIG_MCA is not set +# CONFIG_MCORE2 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MEMTEST is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MICROCODE is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MPENTIUM4 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPSC is not set +# CONFIG_MTD_CFI_INTELEXT is not set +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_NETSC520 is not set +CONFIG_MTD_PHYSMAP=y +# CONFIG_MTD_R8610 is not set +# CONFIG_MTD_RDC3210 is not set +# CONFIG_MTD_TS5500 is not set +# CONFIG_MTRR is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MWINCHIPC6 is not set +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +# CONFIG_NETDEV_1000 is not set +CONFIG_NOHIGHMEM=y +CONFIG_NR_CPUS=1 +# CONFIG_NSC_GPIO is not set +# CONFIG_OLPC is not set +# CONFIG_OPTIMIZE_INLINING is not set +CONFIG_OUTPUT_FORMAT="elf32-i386" +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PARAVIRT_GUEST is not set +# CONFIG_PC8736x_GPIO is not set +# CONFIG_PC87413_WDT is not set +# CONFIG_PCIEPORTBUS is not set +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_DISABLE_COMMON_QUIRKS=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_GOANY=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GOOLPC is not set +# CONFIG_PCI_QUIRKS is not set +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_PHYSICAL_START=0x100000 +CONFIG_PROCESSOR_SELECT=y +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +CONFIG_RDC321X_WDT=m +# CONFIG_RELOCATABLE is not set +# CONFIG_RTC is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_SBC7240_WDT is not set +# CONFIG_SBC8360_WDT is not set +# CONFIG_SBC_EPX_C3_WATCHDOG is not set +# CONFIG_SC1200_WDT is not set +# CONFIG_SC520_WDT is not set +# CONFIG_SCHED_HRTICK is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCSI_DMA is not set +# CONFIG_SCx200 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SHMEM is not set +# CONFIG_SMSC37B787_WDT is not set +# CONFIG_SMSC_SCH311X_WDT is not set +CONFIG_SPARSEMEM_STATIC=y +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_TOSHIBA is not set +# CONFIG_TREE_PREEMPT_RCU is not set +CONFIG_TREE_RCU=y +CONFIG_UID16=y +CONFIG_USB_SUPPORT=y +CONFIG_USER_STACKTRACE_SUPPORT=y +# CONFIG_VM86 is not set +# CONFIG_W83697UG_WDT is not set +# CONFIG_WAFER_WDT is not set +CONFIG_X86=y +CONFIG_X86_32=y +CONFIG_X86_32_LAZY_GS=y +# CONFIG_X86_64 is not set +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_BSWAP=y +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_CMPXCHG=y +CONFIG_X86_CPU=y +# CONFIG_X86_CPUID is not set +# CONFIG_X86_ELAN is not set +CONFIG_X86_EXTENDED_PLATFORM=y +CONFIG_X86_F00F_BUG=y +# CONFIG_X86_GENERIC is not set +CONFIG_X86_INTERNODE_CACHE_BYTES=64 +CONFIG_X86_INVLPG=y +CONFIG_X86_L1_CACHE_BYTES=64 +CONFIG_X86_L1_CACHE_SHIFT=4 +# CONFIG_X86_MCE is not set +CONFIG_X86_MINIMUM_CPU_FAMILY=4 +# CONFIG_X86_MRST is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_PAE is not set +# CONFIG_X86_PLATFORM_DEVICES is not set +CONFIG_X86_POPAD_OK=y +# CONFIG_X86_PPRO_FENCE is not set +CONFIG_X86_RDC321X=y +CONFIG_X86_REBOOTFIXUPS=y +# CONFIG_X86_RESERVE_LOW_64K is not set +# CONFIG_X86_UP_APIC is not set +# CONFIG_X86_VERBOSE_BOOTUP is not set +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_XADD=y +# CONFIG_ZONE_DMA32 is not set diff --git a/target/linux/rdc/files-2.6.32/arch/x86/include/asm/rdc321x_gpio.h b/target/linux/rdc/files-2.6.32/arch/x86/include/asm/rdc321x_gpio.h new file mode 100644 index 000000000..adb75aff2 --- /dev/null +++ b/target/linux/rdc/files-2.6.32/arch/x86/include/asm/rdc321x_gpio.h @@ -0,0 +1,16 @@ +#ifndef _ASM_X86_MACH_RDC321X_GPIO_H +#define _ASM_X86_MACH_RDC321X_GPIO_H + +#include + +#define gpio_to_irq(gpio) NULL + +#define gpio_get_value __gpio_get_value +#define gpio_set_value __gpio_set_value + +#define gpio_cansleep __gpio_cansleep + +/* For cansleep */ +#include + +#endif /* _ASM_X86_MACH_RDC321X_GPIO_H */ diff --git a/target/linux/rdc/files-2.6.32/arch/x86/mach-rdc321x/Makefile b/target/linux/rdc/files-2.6.32/arch/x86/mach-rdc321x/Makefile new file mode 100644 index 000000000..8325b4ca4 --- /dev/null +++ b/target/linux/rdc/files-2.6.32/arch/x86/mach-rdc321x/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the RDC321x specific parts of the kernel +# +obj-$(CONFIG_X86_RDC321X) := gpio.o platform.o + diff --git a/target/linux/rdc/files-2.6.32/arch/x86/mach-rdc321x/gpio.c b/target/linux/rdc/files-2.6.32/arch/x86/mach-rdc321x/gpio.c new file mode 100644 index 000000000..c99b3b223 --- /dev/null +++ b/target/linux/rdc/files-2.6.32/arch/x86/mach-rdc321x/gpio.c @@ -0,0 +1,158 @@ +/* + * GPIO support for RDC SoC R3210/R8610 + * + * Copyright (C) 2007, Florian Fainelli + * Copyright (C) 2008, Volker Weiss + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#include +#include +#include +#include + +#include +#include + + +/* spin lock to protect our private copy of GPIO data register plus + the access to PCI conf registers. */ +static DEFINE_SPINLOCK(gpio_lock); + +/* copy of GPIO data registers */ +static u32 gpio_data_reg1; +static u32 gpio_data_reg2; + +static inline void rdc321x_conf_write(unsigned addr, u32 value) +{ + outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); + outl(value, RDC3210_CFGREG_DATA); +} + +static inline void rdc321x_conf_or(unsigned addr, u32 value) +{ + outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); + value |= inl(RDC3210_CFGREG_DATA); + outl(value, RDC3210_CFGREG_DATA); +} + +static inline u32 rdc321x_conf_read(unsigned addr) +{ + outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); + + return inl(RDC3210_CFGREG_DATA); +} + +/* configure pin as GPIO */ +static void rdc321x_configure_gpio(unsigned gpio) +{ + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + rdc321x_conf_or(gpio < 32 + ? RDC321X_GPIO_CTRL_REG1 : RDC321X_GPIO_CTRL_REG2, + 1 << (gpio & 0x1f)); + spin_unlock_irqrestore(&gpio_lock, flags); +} + +/* read GPIO pin */ +static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + u32 reg; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + reg = rdc321x_conf_read(gpio < 32 + ? RDC321X_GPIO_DATA_REG1 : RDC321X_GPIO_DATA_REG2); + spin_unlock_irqrestore(&gpio_lock, flags); + + return (1 << (gpio & 0x1f)) & reg ? 1 : 0; +} + +/* set GPIO pin to value */ +static void rdc_gpio_set_value(struct gpio_chip *chip, + unsigned gpio, int value) +{ + unsigned long flags; + u32 reg; + + reg = 1 << (gpio & 0x1f); + if (gpio < 32) { + spin_lock_irqsave(&gpio_lock, flags); + if (value) + gpio_data_reg1 |= reg; + else + gpio_data_reg1 &= ~reg; + rdc321x_conf_write(RDC321X_GPIO_DATA_REG1, gpio_data_reg1); + spin_unlock_irqrestore(&gpio_lock, flags); + } else { + spin_lock_irqsave(&gpio_lock, flags); + if (value) + gpio_data_reg2 |= reg; + else + gpio_data_reg2 &= ~reg; + rdc321x_conf_write(RDC321X_GPIO_DATA_REG2, gpio_data_reg2); + spin_unlock_irqrestore(&gpio_lock, flags); + } +} + +/* configure GPIO pin as input */ +static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + rdc321x_configure_gpio(gpio); + + return 0; +} + +/* configure GPIO pin as output and set value */ +static int rdc_gpio_direction_output(struct gpio_chip *chip, + unsigned gpio, int value) +{ + rdc321x_configure_gpio(gpio); + gpio_set_value(gpio, value); + + return 0; +} + +static struct gpio_chip rdc321x_gpio_chip = { + .label = "rdc321x-gpio", + .direction_input = rdc_gpio_direction_input, + .direction_output = rdc_gpio_direction_output, + .get = rdc_gpio_get_value, + .set = rdc_gpio_set_value, + .base = 0, + .ngpio = RDC321X_MAX_GPIO, +}; + +/* initially setup the 2 copies of the gpio data registers. + This function is called before the platform setup code. */ +static int __init rdc321x_gpio_setup(void) +{ + /* this might not be, what others (BIOS, bootloader, etc.) + wrote to these registers before, but it's a good guess. Still + better than just using 0xffffffff. */ + + gpio_data_reg1 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG1); + gpio_data_reg2 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG2); + + printk(KERN_INFO "rdc321x: registering %d GPIOs\n", rdc321x_gpio_chip.ngpio); + return gpiochip_add(&rdc321x_gpio_chip); +} + +arch_initcall(rdc321x_gpio_setup); diff --git a/target/linux/rdc/files-2.6.32/arch/x86/mach-rdc321x/platform.c b/target/linux/rdc/files-2.6.32/arch/x86/mach-rdc321x/platform.c new file mode 100644 index 000000000..3c2cec721 --- /dev/null +++ b/target/linux/rdc/files-2.6.32/arch/x86/mach-rdc321x/platform.c @@ -0,0 +1,290 @@ +/* + * Generic RDC321x platform devices + * + * Copyright (C) 2007-2009 OpenWrt.org + * Copyright (C) 2007 Florian Fainelli + * Copyright (C) 2008-2009 Daniel Gimpelevich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Flash */ +#ifdef CONFIG_MTD_R8610 +#define CONFIG_MTD_RDC3210 1 +#elif defined CONFIG_MTD_RDC3210 +static struct resource rdc_flash_resource[] = { + [0] = { + .start = (u32)-CONFIG_MTD_RDC3210_SIZE, + .end = (u32)-1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device rdc_flash_device = { + .name = "rdc321x-flash", + .id = -1, + .num_resources = ARRAY_SIZE(rdc_flash_resource), + .resource = rdc_flash_resource, +}; +#else +static struct mtd_partition rdc_flash_parts[15]; + +static struct resource rdc_flash_resource = { + .end = (u32)-1, + .flags = IORESOURCE_MEM, +}; + +static struct physmap_flash_data rdc_flash_data = { + .parts = rdc_flash_parts, +}; + +static struct platform_device rdc_flash_device = { + .name = "physmap-flash", + .id = -1, + .resource = &rdc_flash_resource, + .num_resources = 1, + .dev.platform_data = &rdc_flash_data, +}; +#endif + +/* LEDS */ +static struct gpio_led default_leds[] = { + { .name = "rdc321x:dmz", .gpio = 1, .active_low = 1}, +}; + +static struct gpio_led_platform_data rdc321x_led_data = { + .num_leds = ARRAY_SIZE(default_leds), + .leds = default_leds, +}; + +static struct platform_device rdc321x_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &rdc321x_led_data, + } +}; + +/* Watchdog */ +static struct platform_device rdc321x_wdt = { + .name = "rdc321x-wdt", + .id = -1, + .num_resources = 0, +}; + +/* Button */ +static struct gpio_keys_button rdc321x_gpio_btn[] = { + { + .gpio = 0, + .code = BTN_0, + .desc = "Reset", + .active_low = 1, + } +}; + +static struct gpio_keys_platform_data rdc321x_gpio_btn_data = { + .buttons = rdc321x_gpio_btn, + .nbuttons = ARRAY_SIZE(rdc321x_gpio_btn), +}; + +static struct platform_device rdc321x_button = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &rdc321x_gpio_btn_data, + } +}; + +static struct platform_device *rdc321x_devs[] = { + &rdc_flash_device, + &rdc321x_leds, + &rdc321x_wdt, + &rdc321x_button, +}; + +static int probe_flash_start(struct map_info *the_map) +{ + struct mtd_info *res; + + the_map->virt = ioremap(the_map->phys, the_map->size); + if (the_map->virt == NULL) + return 1; + for (the_map->bankwidth = 32; the_map->bankwidth; the_map->bankwidth + >>= 1) { + res = do_map_probe("cfi_probe", the_map); + if (res == NULL) + res = do_map_probe("jedec_probe", the_map); + if (res != NULL) + break; + } + iounmap(the_map->virt); + if (res != NULL) + the_map->phys = (u32)-(s32)(the_map->size = res->size); + return res == NULL; +} + +static int __init rdc_board_setup(void) +{ +#ifndef CONFIG_MTD_RDC3210 + struct map_info rdc_map_info; + u32 the_header[8]; + + ROOT_DEV = 0; + rdc_map_info.name = rdc_flash_device.name; + rdc_map_info.size = 0x800000; //8MB + rdc_map_info.phys = (u32) -rdc_map_info.size; + rdc_map_info.bankwidth = 2; + rdc_map_info.set_vpp = NULL; + simple_map_init(&rdc_map_info); + while (probe_flash_start(&rdc_map_info)) { + if (rdc_map_info.size /= 2 < 0x100000) //1MB + panic("Could not find start of flash!"); + rdc_map_info.phys = (u32) -rdc_map_info.size; + } + rdc_flash_resource.start = rdc_map_info.phys; + rdc_flash_data.width = rdc_map_info.bankwidth; + rdc_map_info.virt = ioremap_nocache(rdc_map_info.phys, 0x10); + if (rdc_map_info.virt == NULL) + panic("Could not ioremap to read device magic!"); + the_header[0] = ((u32 *)rdc_map_info.virt)[0]; + the_header[1] = ((u32 *)rdc_map_info.virt)[1]; + the_header[2] = ((u32 *)rdc_map_info.virt)[2]; + the_header[3] = ((u32 *)rdc_map_info.virt)[3]; + iounmap(rdc_map_info.virt); + rdc_map_info.virt = ioremap_nocache(rdc_map_info.phys + 0x8000, 0x10); + if (rdc_map_info.virt == NULL) + panic("Could not ioremap to read device magic!"); + the_header[4] = ((u32 *)rdc_map_info.virt)[0]; + the_header[5] = ((u32 *)rdc_map_info.virt)[1]; + the_header[6] = ((u32 *)rdc_map_info.virt)[2]; + the_header[7] = ((u32 *)rdc_map_info.virt)[3]; + iounmap(rdc_map_info.virt); + if (!memcmp(the_header, "GMTK", 4)) { /* Gemtek */ + /* TODO */ + } else if (!memcmp(the_header + 4, "CSYS", 4)) { /* Sitecom */ + rdc_flash_parts[0].name = "system"; + rdc_flash_parts[0].offset = 0; + rdc_flash_parts[0].size = rdc_map_info.size - 0x10000; + rdc_flash_parts[1].name = "config"; + rdc_flash_parts[1].offset = 0; + rdc_flash_parts[1].size = 0x8000; + rdc_flash_parts[2].name = "magic"; + rdc_flash_parts[2].offset = 0x8000; + rdc_flash_parts[2].size = 0x14; + rdc_flash_parts[3].name = "kernel"; + rdc_flash_parts[3].offset = 0x8014; + rdc_flash_parts[3].size = the_header[5]; + rdc_flash_parts[4].name = "rootfs"; + rdc_flash_parts[4].offset = 0x8014 + the_header[5]; + rdc_flash_parts[4].size = rdc_flash_parts[0].size - rdc_flash_parts[4].offset; + rdc_flash_parts[5].name = "bootloader"; + rdc_flash_parts[5].offset = rdc_flash_parts[0].size; + rdc_flash_parts[5].size = 0x10000; + rdc_flash_data.nr_parts = 6; + } else if (!memcmp(((u8 *)the_header) + 14, "Li", 2)) { /* AMIT */ + rdc_flash_parts[0].name = "kernel_parthdr"; + rdc_flash_parts[0].offset = 0; + rdc_flash_parts[0].size = 0x10; + rdc_flash_parts[1].name = "kernel"; + rdc_flash_parts[1].offset = 0x10; + rdc_flash_parts[1].size = 0xffff0; + rdc_flash_parts[2].name = "rootfs_parthdr"; + rdc_flash_parts[2].offset = 0x100000; + rdc_flash_parts[2].size = 0x10; + rdc_flash_parts[3].name = "rootfs"; + rdc_flash_parts[3].offset = 0x100010; + rdc_flash_parts[3].size = rdc_map_info.size - 0x160010; + rdc_flash_parts[4].name = "config_parthdr"; + rdc_flash_parts[4].offset = rdc_map_info.size - 0x60000; + rdc_flash_parts[4].size = 0x10; + rdc_flash_parts[5].name = "config"; + rdc_flash_parts[5].offset = rdc_map_info.size - 0x5fff0; + rdc_flash_parts[5].size = 0xfff0; + rdc_flash_parts[6].name = "recoveryfs_parthdr"; + rdc_flash_parts[6].offset = rdc_map_info.size - 0x50000; + rdc_flash_parts[6].size = 0x10; + rdc_flash_parts[7].name = "recoveryfs"; + rdc_flash_parts[7].offset = rdc_map_info.size - 0x4fff0; + rdc_flash_parts[7].size = 0x3fff0; + rdc_flash_parts[8].name = "recovery_parthdr"; + rdc_flash_parts[8].offset = rdc_map_info.size - 0x10000; + rdc_flash_parts[8].size = 0x10; + rdc_flash_parts[9].name = "recovery"; + rdc_flash_parts[9].offset = rdc_map_info.size - 0xfff0; + rdc_flash_parts[9].size = 0x7ff0; + rdc_flash_parts[10].name = "productinfo_parthdr"; + rdc_flash_parts[10].offset = rdc_map_info.size - 0x8000; + rdc_flash_parts[10].size = 0x10; + rdc_flash_parts[11].name = "productinfo"; + rdc_flash_parts[11].offset = rdc_map_info.size - 0x7ff0; + rdc_flash_parts[11].size = 0x1ff0; + rdc_flash_parts[12].name = "bootloader_parthdr"; + rdc_flash_parts[12].offset = rdc_map_info.size - 0x6000; + rdc_flash_parts[12].size = 0x10; + rdc_flash_parts[13].name = "bootloader"; + rdc_flash_parts[13].offset = rdc_map_info.size - 0x5ff0; + rdc_flash_parts[13].size = 0x5ff0; + rdc_flash_parts[14].name = "everything"; + rdc_flash_parts[14].offset = 0; + rdc_flash_parts[14].size = rdc_map_info.size; + rdc_flash_data.nr_parts = 15; + } else { /* ZyXEL */ + rdc_flash_parts[0].name = "kernel"; + rdc_flash_parts[0].offset = 0; + rdc_flash_parts[0].size = 0x100000; + rdc_flash_parts[1].name = "rootfs"; + rdc_flash_parts[1].offset = 0x100000; + rdc_flash_parts[1].size = rdc_map_info.size - 0x140000; + rdc_flash_parts[2].name = "linux"; + rdc_flash_parts[2].offset = 0; + rdc_flash_parts[2].size = rdc_map_info.size - 0x40000; + rdc_flash_parts[3].name = "config"; + rdc_flash_parts[3].offset = rdc_map_info.size - 0x40000; + rdc_flash_parts[3].size = 0x10000; + rdc_flash_parts[4].name = "productinfo"; + rdc_flash_parts[4].offset = rdc_map_info.size - 0x30000; + rdc_flash_parts[4].size = 0x10000; + rdc_flash_parts[5].name = "bootloader"; + rdc_flash_parts[5].offset = rdc_map_info.size - 0x20000; + rdc_flash_parts[5].size = 0x20000; + rdc_flash_data.nr_parts = 6; + } +#endif + return platform_add_devices(rdc321x_devs, ARRAY_SIZE(rdc321x_devs)); +} + +#ifdef CONFIG_MTD_RDC3210 +arch_initcall(rdc_board_setup); +#else +late_initcall(rdc_board_setup); +#endif diff --git a/target/linux/rdc/patches-2.6.32/001-rdc3210_flash_map.patch b/target/linux/rdc/patches-2.6.32/001-rdc3210_flash_map.patch new file mode 100644 index 000000000..01b416260 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/001-rdc3210_flash_map.patch @@ -0,0 +1,63 @@ +--- a/drivers/mtd/maps/Kconfig ++++ b/drivers/mtd/maps/Kconfig +@@ -114,6 +114,50 @@ config MTD_SUN_UFLASH + Sun Microsystems boardsets. This driver will require CFI support + in the kernel, so if you did not enable CFI previously, do that now. + ++config MTD_RDC3210 ++ tristate "CFI Flash device mapped on RDC3210" ++ depends on X86 && MTD_CFI && MTD_PARTITIONS ++ help ++ RDC-3210 is the flash device we find on Ralink reference board. ++ ++config MTD_RDC3210_STATIC_MAP ++ bool "Partitions on RDC3210 mapped statically" if MTD_RDC3210 ++ select MTD_RDC3210_FACTORY_PRESENT ++ help ++ The mapping driver will use the static partition map for the ++ RDC-3210 flash device. ++ ++config MTD_RDC3210_FACTORY_PRESENT ++ bool "Reserve a partition on RDC3210 for factory presets" ++ depends on MTD_RDC3210 ++ default y ++ help ++ The mapping driver will reserve a partition on the RDC-3210 flash ++ device for resetting flash contents to factory defaults. ++ ++config MTD_RDC3210_ALLOW_JFFS2 ++ bool "JFFS2 filesystem usable in a partition on RDC3210" ++ depends on MTD_RDC3210 && !MTD_RDC3210_STATIC_MAP ++ help ++ The mapping driver will align a partition on the RDC-3210 flash ++ device to an erase-block boundary so that a JFFS2 filesystem may ++ reside on it. ++ ++config MTD_RDC3210_SIZE ++ hex "Amount of flash memory on RDC3210" ++ depends on MTD_RDC3210 ++ default "0x400000" ++ help ++ Total size in bytes of the RDC-3210 flash device ++ ++config MTD_RDC3210_BUSWIDTH ++ int "Width of CFI Flash device mapped on RDC3210" ++ depends on MTD_RDC3210 ++ default "2" ++ help ++ Number of bytes addressed on the RDC-3210 flash device before ++ addressing the same chip again ++ + config MTD_SC520CDP + tristate "CFI Flash device mapped on AMD SC520 CDP" + depends on X86 && MTD_CFI && MTD_CONCAT +--- a/drivers/mtd/maps/Makefile ++++ b/drivers/mtd/maps/Makefile +@@ -26,6 +26,7 @@ obj-$(CONFIG_MTD_PHYSMAP) += physmap.o + obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o + obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o + obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o ++obj-$(CONFIG_MTD_RDC3210) += rdc3210.o + obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o + obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o + obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o diff --git a/target/linux/rdc/patches-2.6.32/002-platform_support.patch b/target/linux/rdc/patches-2.6.32/002-platform_support.patch new file mode 100644 index 000000000..26b732a3f --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/002-platform_support.patch @@ -0,0 +1,12 @@ +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -125,6 +125,9 @@ libs-y += arch/x86/lib/ + # See arch/x86/Kbuild for content of core part of the kernel + core-y += arch/x86/ + ++# RDC R-321X support ++core-$(CONFIG_X86_RDC321X) += arch/x86/mach-rdc321x/ ++ + # drivers-y are linked after core-y + drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ + drivers-$(CONFIG_PCI) += arch/x86/pci/ diff --git a/target/linux/rdc/patches-2.6.32/004-yenta_mystery.patch b/target/linux/rdc/patches-2.6.32/004-yenta_mystery.patch new file mode 100644 index 000000000..92589ea54 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/004-yenta_mystery.patch @@ -0,0 +1,20 @@ +--- a/drivers/pcmcia/yenta_socket.c ++++ b/drivers/pcmcia/yenta_socket.c +@@ -1174,6 +1174,17 @@ static int __devinit yenta_probe (struct + + /* We must finish initialization here */ + ++#ifdef CONFIG_X86_RDC321X ++/* #define YO_TI1510_DATASHEET_GUY_EXPLAIN_THIS_JUNK 0x0044f044 */ ++#define YO_TI1510_DATASHEET_GUY_EXPLAIN_THIS_JUNK 0x0844b060 ++/* #define YO_TI1510_DATASHEET_GUY_EXPLAIN_THIS_JUNK 0x0044d044 */ ++ ++ config_writel(socket, 32*4, YO_TI1510_DATASHEET_GUY_EXPLAIN_THIS_JUNK); ++ config_writel(socket, 35*4, 0x00000022); ++ config_writel(socket, 36*4, 0x60200000); ++ config_writel(socket, 40*4, 0x7e020000); ++#endif ++ + if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, IRQF_SHARED, "yenta", socket)) { + /* No IRQ or request_irq failed. Poll */ + socket->cb_irq = 0; /* But zero is a valid IRQ number. */ diff --git a/target/linux/rdc/patches-2.6.32/005-fix_amit_breakage.patch b/target/linux/rdc/patches-2.6.32/005-fix_amit_breakage.patch new file mode 100644 index 000000000..decaf8c44 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/005-fix_amit_breakage.patch @@ -0,0 +1,40 @@ +--- a/arch/x86/boot/boot.h ++++ b/arch/x86/boot/boot.h +@@ -64,7 +64,7 @@ static inline void outl(u32 v, u16 port) + { + asm volatile("outl %0,%1" : : "a" (v), "dN" (port)); + } +-static inline u32 inl(u32 port) ++static inline u32 inl(u16 port) + { + u32 v; + asm volatile("inl %1,%0" : "=a" (v) : "dN" (port)); +--- a/arch/x86/boot/pm.c ++++ b/arch/x86/boot/pm.c +@@ -14,6 +14,9 @@ + + #include "boot.h" + #include ++#ifdef CONFIG_X86_RDC321X ++#include ++#endif + + /* + * Invoke the realmode switch hook if present; otherwise +@@ -112,6 +115,16 @@ void go_to_protected_mode(void) + die(); + } + ++#ifdef CONFIG_X86_RDC321X ++ { ++ u32 bootctl; ++ ++ outl(0x80003840, RDC3210_CFGREG_ADDR); ++ bootctl = inl(RDC3210_CFGREG_DATA) | 0x07ff0000; ++ outl(bootctl, RDC3210_CFGREG_DATA); ++ } ++#endif ++ + /* Reset coprocessor (IGNNE#) */ + reset_coprocessor(); + diff --git a/target/linux/rdc/patches-2.6.32/008-r8610_flash_map.patch b/target/linux/rdc/patches-2.6.32/008-r8610_flash_map.patch new file mode 100644 index 000000000..0f06beb09 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/008-r8610_flash_map.patch @@ -0,0 +1,25 @@ +--- a/drivers/mtd/maps/Kconfig ++++ b/drivers/mtd/maps/Kconfig +@@ -158,6 +158,12 @@ config MTD_RDC3210_BUSWIDTH + Number of bytes addressed on the RDC-3210 flash device before + addressing the same chip again + ++config MTD_R8610 ++ tristate "CFI flash device mapped on R8610" ++ depends on X86 && MTD_CFI && MTD_PARTITIONS ++ help ++ Flash support for the RDC R8610 evaluation board. ++ + config MTD_SC520CDP + tristate "CFI Flash device mapped on AMD SC520 CDP" + depends on X86 && MTD_CFI && MTD_CONCAT +--- a/drivers/mtd/maps/Makefile ++++ b/drivers/mtd/maps/Makefile +@@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_ + obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o + obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o + obj-$(CONFIG_MTD_RDC3210) += rdc3210.o ++obj-$(CONFIG_MTD_R8610) += r8610.o + obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o + obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o + obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o diff --git a/target/linux/rdc/patches-2.6.32/009-rdc321x_select_embedded.patch b/target/linux/rdc/patches-2.6.32/009-rdc321x_select_embedded.patch new file mode 100644 index 000000000..625dc6531 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/009-rdc321x_select_embedded.patch @@ -0,0 +1,11 @@ +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -400,6 +400,8 @@ config X86_RDC321X + depends on X86_EXTENDED_PLATFORM + select M486 + select X86_REBOOTFIXUPS ++ select EMBEDDED ++ select ARCH_REQUIRE_GPIOLIB + ---help--- + This option is needed for RDC R-321x system-on-chip, also known + as R-8610-(G). diff --git a/target/linux/rdc/patches-2.6.32/010-rdc_cpu_ident.patch b/target/linux/rdc/patches-2.6.32/010-rdc_cpu_ident.patch new file mode 100644 index 000000000..918daf10d --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/010-rdc_cpu_ident.patch @@ -0,0 +1,176 @@ +--- /dev/null ++++ b/Documentation/x86/rdc.txt +@@ -0,0 +1,69 @@ ++ ++Introduction ++============ ++ ++RDC (http://www.rdc.com.tw) have been manufacturing x86-compatible SoC ++(system-on-chips) for a number of years. They are not the fastest of ++CPUs (clock speeds ranging from 133-150MHz) but 486SX compatibility ++coupled with very low power consumption[1] and low cost make them ideal ++for embedded applications. ++ ++ ++Where to find ++============= ++ ++RDC chips show up in numerous embedded devices, but be careful since ++many of them will not run Linux 2.6 without significant expertise. ++ ++There are several variants of what the linux kernel refers to generically ++as RDC321X: R8610, R321x, S3282 and AMRISC20000. ++ ++R321x: Found in various routers, see the OpenWrt project for details, ++ http://wiki.openwrt.org/oldwiki/rdcport ++ ++R8610: Found on the RDC evaluation board ++ http://www.ivankuten.com/system-on-chip-soc/rdc-r8610/ ++ ++AMRISC20000: Found in the MGB-100 wireless hard disk ++ http://tintuc.no-ip.com/linux/tipps/mgb100/ ++ ++S3282: Found in various NAS devices, including the Bifferboard ++ http://www.bifferos.com ++ ++ ++Kernel Configuration ++==================== ++ ++Add support for this CPU with CONFIG_X86_RDC321X. Ensure that maths ++emulation is included (CONFIG_MATH_EMULATION selected) and avoid MCE ++(CONFIG_X86_MCE not selected). ++ ++ ++CPU detection ++============= ++ ++None of these chips support the cpuid instruction, so as with some ++other x86 compatible SoCs, we must check the north bridge and look ++for specific 'signature' PCI device config. ++ ++The current detection code has been tested only on the Bifferboard ++(S3282 CPU), please send bug reports or success stories with ++other devices to bifferos@yahoo.co.uk. ++ ++ ++Credits ++======= ++ ++Many thanks to RDC for providing the customer codes to allow ++detection of all known variants, without which this detection code ++would have been very hard to ascertain. ++ ++ ++References ++========== ++ ++[1] S3282 in certain NAS solutions consumes less than 1W ++ ++ ++mark@bifferos.com 2009 ++ +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -398,6 +398,7 @@ config X86_RDC321X + bool "RDC R-321x SoC" + depends on X86_32 + depends on X86_EXTENDED_PLATFORM ++ select PCI + select M486 + select X86_REBOOTFIXUPS + select EMBEDDED +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -122,7 +122,8 @@ struct cpuinfo_x86 { + #define X86_VENDOR_CENTAUR 5 + #define X86_VENDOR_TRANSMETA 7 + #define X86_VENDOR_NSC 8 +-#define X86_VENDOR_NUM 9 ++#define X86_VENDOR_RDC 9 ++#define X86_VENDOR_NUM 10 + + #define X86_VENDOR_UNKNOWN 0xff + +--- a/arch/x86/kernel/cpu/Makefile ++++ b/arch/x86/kernel/cpu/Makefile +@@ -24,6 +24,7 @@ obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix + obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o + obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o + obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o ++obj-$(CONFIG_X86_RDC321X) += rdc.o + + obj-$(CONFIG_PERF_EVENTS) += perf_event.o + +--- /dev/null ++++ b/arch/x86/kernel/cpu/rdc.c +@@ -0,0 +1,69 @@ ++/* ++ * See Documentation/x86/rdc.txt ++ * ++ * mark@bifferos.com ++ */ ++ ++#include ++#include ++#include "cpu.h" ++ ++ ++static void __cpuinit rdc_identify(struct cpuinfo_x86 *c) ++{ ++ u16 vendor, device; ++ u32 customer_id; ++ ++ if (!early_pci_allowed()) ++ return; ++ ++ /* RDC CPU is SoC (system-on-chip), Northbridge is always present */ ++ vendor = read_pci_config_16(0, 0, 0, PCI_VENDOR_ID); ++ device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID); ++ ++ if (vendor != PCI_VENDOR_ID_RDC || device != PCI_DEVICE_ID_RDC_R6020) ++ return; /* not RDC */ ++ /* ++ * NB: We could go on and check other devices, e.g. r6040 NIC, but ++ * that's probably overkill ++ */ ++ ++ customer_id = read_pci_config(0, 0, 0, 0x90); ++ ++ switch (customer_id) { ++ /* id names are from RDC */ ++ case 0x00321000: ++ strcpy(c->x86_model_id, "R3210/R3211"); ++ break; ++ case 0x00321001: ++ strcpy(c->x86_model_id, "AMITRISC20000/20010"); ++ break; ++ case 0x00321002: ++ strcpy(c->x86_model_id, "R3210X/Edimax"); ++ break; ++ case 0x00321003: ++ strcpy(c->x86_model_id, "R3210/Kcodes"); ++ break; ++ case 0x00321004: /* tested */ ++ strcpy(c->x86_model_id, "S3282/CodeTek"); ++ break; ++ case 0x00321007: ++ strcpy(c->x86_model_id, "R8610"); ++ break; ++ default: ++ pr_info("RDC CPU: Unrecognised Customer ID (0x%x) please report to linux-kernel@vger.kernel.org\n", customer_id); ++ return; ++ } ++ ++ strcpy(c->x86_vendor_id, "RDC"); ++ c->x86_vendor = X86_VENDOR_RDC; ++} ++ ++static const struct cpu_dev __cpuinitconst rdc_cpu_dev = { ++ .c_vendor = "RDC", ++ .c_ident = { "RDC" }, ++ .c_identify = rdc_identify, ++ .c_x86_vendor = X86_VENDOR_RDC, ++}; ++ ++cpu_dev_register(rdc_cpu_dev); diff --git a/target/linux/sibyte/Makefile b/target/linux/sibyte/Makefile index bfcd648cc..9146be55e 100644 --- a/target/linux/sibyte/Makefile +++ b/target/linux/sibyte/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2006-2009 OpenWrt.org +# Copyright (C) 2006-2010 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -12,7 +12,7 @@ BOARDNAME:=Broadcom/SiByte SB-1 FEATURES:=fpu CFLAGS:=-Os -pipe -march=sb1 -funit-at-a-time -LINUX_VERSION:=2.6.30.10 +LINUX_VERSION:=2.6.32.8 include $(INCLUDE_DIR)/target.mk diff --git a/target/linux/sibyte/config-default b/target/linux/sibyte/config-default index 7d572d958..22dcb126c 100644 --- a/target/linux/sibyte/config-default +++ b/target/linux/sibyte/config-default @@ -1,5 +1,6 @@ # CONFIG_32BIT is not set CONFIG_64BIT=y +# CONFIG_AR7 is not set # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_ARCH_POPULATES_NODE_MAP=y @@ -8,6 +9,7 @@ CONFIG_ARCH_SUPPORTS_OPROFILE=y CONFIG_ARCH_SUSPEND_POSSIBLE=y # CONFIG_ARPD is not set # CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set # CONFIG_BINARY_PRINTF is not set CONFIG_BINFMT_ELF32=y CONFIG_BITREVERSE=y @@ -107,6 +109,7 @@ CONFIG_LOG_BUF_SHIFT=15 # CONFIG_MACH_ALCHEMY is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_LOONGSON is not set # CONFIG_MACH_TX39XX is not set # CONFIG_MACH_TX49XX is not set # CONFIG_MACH_VR41XX is not set diff --git a/target/linux/sibyte/patches/001-sibyte_remove_simulation.patch b/target/linux/sibyte/patches/001-sibyte_remove_simulation.patch deleted file mode 100644 index c3208a4f7..000000000 --- a/target/linux/sibyte/patches/001-sibyte_remove_simulation.patch +++ /dev/null @@ -1,37 +0,0 @@ -[PATCH] Remove SiByte simulator option - -This patch removes the SiByte simulation Kconfig option, which only -modified a printk. - -Signed-off-by: Imre Kaloz - ---- a/arch/mips/sibyte/Kconfig -+++ b/arch/mips/sibyte/Kconfig -@@ -128,13 +128,6 @@ config SIBYTE_ENABLE_LDT_IF_PCI - bool - select SIBYTE_HAS_LDT if PCI - --config SIMULATION -- bool "Running under simulation" -- depends on SIBYTE_SB1xxx_SOC -- help -- Build a kernel suitable for running under the GDB simulator. -- Primarily adjusts the kernel's notion of time. -- - config SB1_CEX_ALWAYS_FATAL - bool "All cache exceptions considered fatal (no recovery attempted)" - depends on SIBYTE_SB1xxx_SOC ---- a/arch/mips/sibyte/swarm/setup.c -+++ b/arch/mips/sibyte/swarm/setup.c -@@ -137,11 +137,7 @@ void __init plat_mem_setup(void) - swarm_rtc_type = RTC_M4LT81; - - printk("This kernel optimized for " --#ifdef CONFIG_SIMULATION -- "simulation" --#else - "board" --#endif - " runs " - #ifdef CONFIG_SIBYTE_CFE - "with" diff --git a/target/linux/sibyte/patches/002-sibyte_remove_standalone_support.patch b/target/linux/sibyte/patches/002-sibyte_remove_standalone_support.patch deleted file mode 100644 index 2c46ccf66..000000000 --- a/target/linux/sibyte/patches/002-sibyte_remove_standalone_support.patch +++ /dev/null @@ -1,1070 +0,0 @@ -CFE is the only supported and used bootloader on the SiByte boards, -the standalone kernel support has been never used outside Broadcom. -Remove it and make the kernel use CFE by default. - -Signed-off-by: Imre Kaloz - ---- a/arch/mips/Makefile -+++ b/arch/mips/Makefile -@@ -167,7 +167,6 @@ libs-$(CONFIG_ARC) += arch/mips/fw/arc/ - libs-$(CONFIG_CFE) += arch/mips/fw/cfe/ - libs-$(CONFIG_SNIPROM) += arch/mips/fw/sni/ - libs-y += arch/mips/fw/lib/ --libs-$(CONFIG_SIBYTE_CFE) += arch/mips/sibyte/cfe/ - - # - # Board-dependent options and extra files ---- a/arch/mips/sibyte/cfe/console.c -+++ /dev/null -@@ -1,79 +0,0 @@ --#include --#include --#include -- --#include -- --#include --#include -- --extern int cfe_cons_handle; -- --static void cfe_console_write(struct console *cons, const char *str, -- unsigned int count) --{ -- int i, last, written; -- -- for (i=0, last=0; i MAX_RAM_SIZE) -- || (initrd_pend > MAX_RAM_SIZE))) { -- panic("initrd out of addressable memory"); -- } -- --#endif /* INITRD */ -- -- for (idx = 0; cfe_enummem(idx, mem_flags, &addr, &size, &type) != CFE_ERR_NOMORE; -- idx++) { -- rd_flag = 0; -- if (type == CFE_MI_AVAILABLE) { -- /* -- * See if this block contains (any portion of) the -- * ramdisk -- */ --#ifdef CONFIG_BLK_DEV_INITRD -- if (initrd_start) { -- if ((initrd_pstart > addr) && -- (initrd_pstart < (addr + size))) { -- add_memory_region(addr, -- initrd_pstart - addr, -- BOOT_MEM_RAM); -- rd_flag = 1; -- } -- if ((initrd_pend > addr) && -- (initrd_pend < (addr + size))) { -- add_memory_region(initrd_pend, -- (addr + size) - initrd_pend, -- BOOT_MEM_RAM); -- rd_flag = 1; -- } -- } --#endif -- if (!rd_flag) { -- if (addr > MAX_RAM_SIZE) -- continue; -- if (addr+size > MAX_RAM_SIZE) -- size = MAX_RAM_SIZE - (addr+size) + 1; -- /* -- * memcpy/__copy_user prefetch, which -- * will cause a bus error for -- * KSEG/KUSEG addrs not backed by RAM. -- * Hence, reserve some padding for the -- * prefetch distance. -- */ -- if (size > 512) -- size -= 512; -- add_memory_region(addr, size, BOOT_MEM_RAM); -- } -- board_mem_region_addrs[board_mem_region_count] = addr; -- board_mem_region_sizes[board_mem_region_count] = size; -- board_mem_region_count++; -- if (board_mem_region_count == -- SIBYTE_MAX_MEM_REGIONS) { -- /* -- * Too many regions. Need to configure more -- */ -- while(1); -- } -- } -- } --#ifdef CONFIG_BLK_DEV_INITRD -- if (initrd_start) { -- add_memory_region(initrd_pstart, initrd_pend - initrd_pstart, -- BOOT_MEM_RESERVED); -- } --#endif --} -- --#ifdef CONFIG_BLK_DEV_INITRD --static int __init initrd_setup(char *str) --{ -- char rdarg[64]; -- int idx; -- char *tmp, *endptr; -- unsigned long initrd_size; -- -- /* Make a copy of the initrd argument so we can smash it up here */ -- for (idx = 0; idx < sizeof(rdarg)-1; idx++) { -- if (!str[idx] || (str[idx] == ' ')) break; -- rdarg[idx] = str[idx]; -- } -- -- rdarg[idx] = 0; -- str = rdarg; -- -- /* -- *Initrd location comes in the form "@" -- * e.g. initrd=3abfd@80010000. This is set up by the loader. -- */ -- for (tmp = str; *tmp != '@'; tmp++) { -- if (!*tmp) { -- goto fail; -- } -- } -- *tmp = 0; -- tmp++; -- if (!*tmp) { -- goto fail; -- } -- initrd_size = simple_strtoul(str, &endptr, 16); -- if (*endptr) { -- *(tmp-1) = '@'; -- goto fail; -- } -- *(tmp-1) = '@'; -- initrd_start = simple_strtoul(tmp, &endptr, 16); -- if (*endptr) { -- goto fail; -- } -- initrd_end = initrd_start + initrd_size; -- printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start); -- return 1; -- fail: -- printk("Bad initrd argument. Disabling initrd\n"); -- initrd_start = 0; -- initrd_end = 0; -- return 1; --} -- --#endif -- --extern struct plat_smp_ops sb_smp_ops; --extern struct plat_smp_ops bcm1480_smp_ops; -- --/* -- * prom_init is called just after the cpu type is determined, from setup_arch() -- */ --void __init prom_init(void) --{ -- uint64_t cfe_ept, cfe_handle; -- unsigned int cfe_eptseal; -- int argc = fw_arg0; -- char **envp = (char **) fw_arg2; -- int *prom_vec = (int *) fw_arg3; -- -- _machine_restart = cfe_linux_restart; -- _machine_halt = cfe_linux_halt; -- pm_power_off = cfe_linux_halt; -- -- /* -- * Check if a loader was used; if NOT, the 4 arguments are -- * what CFE gives us (handle, 0, EPT and EPTSEAL) -- */ -- if (argc < 0) { -- cfe_handle = (uint64_t)(long)argc; -- cfe_ept = (long)envp; -- cfe_eptseal = (uint32_t)(unsigned long)prom_vec; -- } else { -- if ((int32_t)(long)prom_vec < 0) { -- /* -- * Old loader; all it gives us is the handle, -- * so use the "known" entrypoint and assume -- * the seal. -- */ -- cfe_handle = (uint64_t)(long)prom_vec; -- cfe_ept = (uint64_t)((int32_t)0x9fc00500); -- cfe_eptseal = CFE_EPTSEAL; -- } else { -- /* -- * Newer loaders bundle the handle/ept/eptseal -- * Note: prom_vec is in the loader's useg -- * which is still alive in the TLB. -- */ -- cfe_handle = (uint64_t)((int32_t *)prom_vec)[0]; -- cfe_ept = (uint64_t)((int32_t *)prom_vec)[2]; -- cfe_eptseal = (unsigned int)((uint32_t *)prom_vec)[3]; -- } -- } -- if (cfe_eptseal != CFE_EPTSEAL) { -- /* too early for panic to do any good */ -- printk("CFE's entrypoint seal doesn't match. Spinning."); -- while (1) ; -- } -- cfe_init(cfe_handle, cfe_ept); -- /* -- * Get the handle for (at least) prom_putchar, possibly for -- * boot console -- */ -- cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); -- if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, CL_SIZE) < 0) { -- if (argc >= 0) { -- /* The loader should have set the command line */ -- /* too early for panic to do any good */ -- printk("LINUX_CMDLINE not defined in cfe."); -- while (1) ; -- } -- } -- --#ifdef CONFIG_BLK_DEV_INITRD -- { -- char *ptr; -- /* Need to find out early whether we've got an initrd. So scan -- the list looking now */ -- for (ptr = arcs_cmdline; *ptr; ptr++) { -- while (*ptr == ' ') { -- ptr++; -- } -- if (!strncmp(ptr, "initrd=", 7)) { -- initrd_setup(ptr+7); -- break; -- } else { -- while (*ptr && (*ptr != ' ')) { -- ptr++; -- } -- } -- } -- } --#endif /* CONFIG_BLK_DEV_INITRD */ -- -- /* Not sure this is needed, but it's the safe way. */ -- arcs_cmdline[CL_SIZE-1] = 0; -- -- prom_meminit(); -- --#if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250) -- register_smp_ops(&sb_smp_ops); --#endif --#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) -- register_smp_ops(&bcm1480_smp_ops); --#endif --} -- --void __init prom_free_prom_memory(void) --{ -- /* Not sure what I'm supposed to do here. Nothing, I think */ --} -- --void prom_putchar(char c) --{ -- int ret; -- -- while ((ret = cfe_write(cfe_cons_handle, &c, 1)) == 0) -- ; --} ---- /dev/null -+++ b/arch/mips/sibyte/common/cfe.c -@@ -0,0 +1,350 @@ -+/* -+ * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* Max ram addressable in 32-bit segments */ -+#ifdef CONFIG_64BIT -+#define MAX_RAM_SIZE (~0ULL) -+#else -+#ifdef CONFIG_HIGHMEM -+#ifdef CONFIG_64BIT_PHYS_ADDR -+#define MAX_RAM_SIZE (~0ULL) -+#else -+#define MAX_RAM_SIZE (0xffffffffULL) -+#endif -+#else -+#define MAX_RAM_SIZE (0x1fffffffULL) -+#endif -+#endif -+ -+#define SIBYTE_MAX_MEM_REGIONS 8 -+phys_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS]; -+phys_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS]; -+unsigned int board_mem_region_count; -+ -+int cfe_cons_handle; -+ -+#ifdef CONFIG_BLK_DEV_INITRD -+extern unsigned long initrd_start, initrd_end; -+#endif -+ -+static void __noreturn cfe_linux_exit(void *arg) -+{ -+ int warm = *(int *)arg; -+ -+ if (smp_processor_id()) { -+ static int reboot_smp; -+ -+ /* Don't repeat the process from another CPU */ -+ if (!reboot_smp) { -+ /* Get CPU 0 to do the cfe_exit */ -+ reboot_smp = 1; -+ smp_call_function(cfe_linux_exit, arg, 0); -+ } -+ } else { -+ printk("Passing control back to CFE...\n"); -+ cfe_exit(warm, 0); -+ printk("cfe_exit returned??\n"); -+ } -+ while (1); -+} -+ -+static void __noreturn cfe_linux_restart(char *command) -+{ -+ static const int zero; -+ -+ cfe_linux_exit((void *)&zero); -+} -+ -+static void __noreturn cfe_linux_halt(void) -+{ -+ static const int one = 1; -+ -+ cfe_linux_exit((void *)&one); -+} -+ -+static __init void prom_meminit(void) -+{ -+ u64 addr, size, type; /* regardless of 64BIT_PHYS_ADDR */ -+ int mem_flags = 0; -+ unsigned int idx; -+ int rd_flag; -+#ifdef CONFIG_BLK_DEV_INITRD -+ unsigned long initrd_pstart; -+ unsigned long initrd_pend; -+ -+ initrd_pstart = CPHYSADDR(initrd_start); -+ initrd_pend = CPHYSADDR(initrd_end); -+ if (initrd_start && -+ ((initrd_pstart > MAX_RAM_SIZE) -+ || (initrd_pend > MAX_RAM_SIZE))) { -+ panic("initrd out of addressable memory"); -+ } -+ -+#endif /* INITRD */ -+ -+ for (idx = 0; cfe_enummem(idx, mem_flags, &addr, &size, &type) != CFE_ERR_NOMORE; -+ idx++) { -+ rd_flag = 0; -+ if (type == CFE_MI_AVAILABLE) { -+ /* -+ * See if this block contains (any portion of) the -+ * ramdisk -+ */ -+#ifdef CONFIG_BLK_DEV_INITRD -+ if (initrd_start) { -+ if ((initrd_pstart > addr) && -+ (initrd_pstart < (addr + size))) { -+ add_memory_region(addr, -+ initrd_pstart - addr, -+ BOOT_MEM_RAM); -+ rd_flag = 1; -+ } -+ if ((initrd_pend > addr) && -+ (initrd_pend < (addr + size))) { -+ add_memory_region(initrd_pend, -+ (addr + size) - initrd_pend, -+ BOOT_MEM_RAM); -+ rd_flag = 1; -+ } -+ } -+#endif -+ if (!rd_flag) { -+ if (addr > MAX_RAM_SIZE) -+ continue; -+ if (addr+size > MAX_RAM_SIZE) -+ size = MAX_RAM_SIZE - (addr+size) + 1; -+ /* -+ * memcpy/__copy_user prefetch, which -+ * will cause a bus error for -+ * KSEG/KUSEG addrs not backed by RAM. -+ * Hence, reserve some padding for the -+ * prefetch distance. -+ */ -+ if (size > 512) -+ size -= 512; -+ add_memory_region(addr, size, BOOT_MEM_RAM); -+ } -+ board_mem_region_addrs[board_mem_region_count] = addr; -+ board_mem_region_sizes[board_mem_region_count] = size; -+ board_mem_region_count++; -+ if (board_mem_region_count == -+ SIBYTE_MAX_MEM_REGIONS) { -+ /* -+ * Too many regions. Need to configure more -+ */ -+ while(1); -+ } -+ } -+ } -+#ifdef CONFIG_BLK_DEV_INITRD -+ if (initrd_start) { -+ add_memory_region(initrd_pstart, initrd_pend - initrd_pstart, -+ BOOT_MEM_RESERVED); -+ } -+#endif -+} -+ -+#ifdef CONFIG_BLK_DEV_INITRD -+static int __init initrd_setup(char *str) -+{ -+ char rdarg[64]; -+ int idx; -+ char *tmp, *endptr; -+ unsigned long initrd_size; -+ -+ /* Make a copy of the initrd argument so we can smash it up here */ -+ for (idx = 0; idx < sizeof(rdarg)-1; idx++) { -+ if (!str[idx] || (str[idx] == ' ')) break; -+ rdarg[idx] = str[idx]; -+ } -+ -+ rdarg[idx] = 0; -+ str = rdarg; -+ -+ /* -+ *Initrd location comes in the form "@" -+ * e.g. initrd=3abfd@80010000. This is set up by the loader. -+ */ -+ for (tmp = str; *tmp != '@'; tmp++) { -+ if (!*tmp) { -+ goto fail; -+ } -+ } -+ *tmp = 0; -+ tmp++; -+ if (!*tmp) { -+ goto fail; -+ } -+ initrd_size = simple_strtoul(str, &endptr, 16); -+ if (*endptr) { -+ *(tmp-1) = '@'; -+ goto fail; -+ } -+ *(tmp-1) = '@'; -+ initrd_start = simple_strtoul(tmp, &endptr, 16); -+ if (*endptr) { -+ goto fail; -+ } -+ initrd_end = initrd_start + initrd_size; -+ printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start); -+ return 1; -+ fail: -+ printk("Bad initrd argument. Disabling initrd\n"); -+ initrd_start = 0; -+ initrd_end = 0; -+ return 1; -+} -+ -+#endif -+ -+extern struct plat_smp_ops sb_smp_ops; -+extern struct plat_smp_ops bcm1480_smp_ops; -+ -+/* -+ * prom_init is called just after the cpu type is determined, from setup_arch() -+ */ -+void __init prom_init(void) -+{ -+ uint64_t cfe_ept, cfe_handle; -+ unsigned int cfe_eptseal; -+ int argc = fw_arg0; -+ char **envp = (char **) fw_arg2; -+ int *prom_vec = (int *) fw_arg3; -+ -+ _machine_restart = cfe_linux_restart; -+ _machine_halt = cfe_linux_halt; -+ pm_power_off = cfe_linux_halt; -+ -+ /* -+ * Check if a loader was used; if NOT, the 4 arguments are -+ * what CFE gives us (handle, 0, EPT and EPTSEAL) -+ */ -+ if (argc < 0) { -+ cfe_handle = (uint64_t)(long)argc; -+ cfe_ept = (long)envp; -+ cfe_eptseal = (uint32_t)(unsigned long)prom_vec; -+ } else { -+ if ((int32_t)(long)prom_vec < 0) { -+ /* -+ * Old loader; all it gives us is the handle, -+ * so use the "known" entrypoint and assume -+ * the seal. -+ */ -+ cfe_handle = (uint64_t)(long)prom_vec; -+ cfe_ept = (uint64_t)((int32_t)0x9fc00500); -+ cfe_eptseal = CFE_EPTSEAL; -+ } else { -+ /* -+ * Newer loaders bundle the handle/ept/eptseal -+ * Note: prom_vec is in the loader's useg -+ * which is still alive in the TLB. -+ */ -+ cfe_handle = (uint64_t)((int32_t *)prom_vec)[0]; -+ cfe_ept = (uint64_t)((int32_t *)prom_vec)[2]; -+ cfe_eptseal = (unsigned int)((uint32_t *)prom_vec)[3]; -+ } -+ } -+ if (cfe_eptseal != CFE_EPTSEAL) { -+ /* too early for panic to do any good */ -+ printk("CFE's entrypoint seal doesn't match. Spinning."); -+ while (1) ; -+ } -+ cfe_init(cfe_handle, cfe_ept); -+ /* -+ * Get the handle for (at least) prom_putchar, possibly for -+ * boot console -+ */ -+ cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); -+ if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, CL_SIZE) < 0) { -+ if (argc < 0) { -+ /* -+ * It's OK for direct boot to not provide a -+ * command line -+ */ -+ strcpy(arcs_cmdline, "root=/dev/ram0 "); -+ } else { -+ /* The loader should have set the command line */ -+ /* too early for panic to do any good */ -+ printk("LINUX_CMDLINE not defined in cfe."); -+ while (1) ; -+ } -+ } -+ -+#ifdef CONFIG_BLK_DEV_INITRD -+ { -+ char *ptr; -+ /* Need to find out early whether we've got an initrd. So scan -+ the list looking now */ -+ for (ptr = arcs_cmdline; *ptr; ptr++) { -+ while (*ptr == ' ') { -+ ptr++; -+ } -+ if (!strncmp(ptr, "initrd=", 7)) { -+ initrd_setup(ptr+7); -+ break; -+ } else { -+ while (*ptr && (*ptr != ' ')) { -+ ptr++; -+ } -+ } -+ } -+ } -+#endif /* CONFIG_BLK_DEV_INITRD */ -+ -+ /* Not sure this is needed, but it's the safe way. */ -+ arcs_cmdline[CL_SIZE-1] = 0; -+ -+ prom_meminit(); -+ -+#if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250) -+ register_smp_ops(&sb_smp_ops); -+#endif -+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) -+ register_smp_ops(&bcm1480_smp_ops); -+#endif -+} -+ -+void __init prom_free_prom_memory(void) -+{ -+ /* Not sure what I'm supposed to do here. Nothing, I think */ -+} -+ -+void prom_putchar(char c) -+{ -+ int ret; -+ -+ while ((ret = cfe_write(cfe_cons_handle, &c, 1)) == 0) -+ ; -+} ---- /dev/null -+++ b/arch/mips/sibyte/common/cfe_console.c -@@ -0,0 +1,79 @@ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+ -+extern int cfe_cons_handle; -+ -+static void cfe_console_write(struct console *cons, const char *str, -+ unsigned int count) -+{ -+ int i, last, written; -+ -+ for (i=0, last=0; i --#include --#include --#include --#include --#include --#include --#include -- --#include --#include -- --#define MAX_RAM_SIZE ((CONFIG_SIBYTE_STANDALONE_RAM_SIZE * 1024 * 1024) - 1) -- --static __init void prom_meminit(void) --{ --#ifdef CONFIG_BLK_DEV_INITRD -- unsigned long initrd_pstart; -- unsigned long initrd_pend; -- -- initrd_pstart = __pa(initrd_start); -- initrd_pend = __pa(initrd_end); -- if (initrd_start && -- ((initrd_pstart > MAX_RAM_SIZE) -- || (initrd_pend > MAX_RAM_SIZE))) { -- panic("initrd out of addressable memory"); -- } -- -- add_memory_region(0, initrd_pstart, -- BOOT_MEM_RAM); -- add_memory_region(initrd_pstart, initrd_pend - initrd_pstart, -- BOOT_MEM_RESERVED); -- add_memory_region(initrd_pend, -- (CONFIG_SIBYTE_STANDALONE_RAM_SIZE * 1024 * 1024) - initrd_pend, -- BOOT_MEM_RAM); --#else -- add_memory_region(0, CONFIG_SIBYTE_STANDALONE_RAM_SIZE * 1024 * 1024, -- BOOT_MEM_RAM); --#endif --} -- --void prom_cpu0_exit(void *unused) --{ -- while (1) ; --} -- --static void prom_linux_exit(void) --{ --#ifdef CONFIG_SMP -- if (smp_processor_id()) { -- smp_call_function(prom_cpu0_exit, NULL, 1); -- } --#endif -- while(1); --} -- --/* -- * prom_init is called just after the cpu type is determined, from setup_arch() -- */ --void __init prom_init(void) --{ -- _machine_restart = (void (*)(char *))prom_linux_exit; -- _machine_halt = prom_linux_exit; -- pm_power_off = prom_linux_exit; -- -- strcpy(arcs_cmdline, "root=/dev/ram0 "); -- -- prom_meminit(); --} -- --void __init prom_free_prom_memory(void) --{ -- /* Not sure what I'm supposed to do here. Nothing, I think */ --} -- --void prom_putchar(char c) --{ --} ---- a/arch/mips/sibyte/swarm/setup.c -+++ b/arch/mips/sibyte/swarm/setup.c -@@ -136,16 +136,6 @@ void __init plat_mem_setup(void) - if (m41t81_probe()) - swarm_rtc_type = RTC_M4LT81; - -- printk("This kernel optimized for " -- "board" -- " runs " --#ifdef CONFIG_SIBYTE_CFE -- "with" --#else -- "without" --#endif -- " CFE\n"); -- - #ifdef CONFIG_VT - screen_info = (struct screen_info) { - 0, 0, /* orig-x, orig-y */ diff --git a/target/linux/sibyte/patches/100-honuor_config_cmdline.patch b/target/linux/sibyte/patches/100-honuor_config_cmdline.patch deleted file mode 100644 index 1c3545f74..000000000 --- a/target/linux/sibyte/patches/100-honuor_config_cmdline.patch +++ /dev/null @@ -1,19 +0,0 @@ -The SiByte platform code doesn't honor the CONFIG_CMDLINE kernel -option. This patch fixes this issue. - -Signed-off-by: Imre Kaloz - ---- a/arch/mips/sibyte/common/cfe.c -+++ b/arch/mips/sibyte/common/cfe.c -@@ -293,7 +293,11 @@ void __init prom_init(void) - * It's OK for direct boot to not provide a - * command line - */ -+#ifdef CONFIG_CMDLINE -+ strlcpy(arcs_cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE); -+#else - strcpy(arcs_cmdline, "root=/dev/ram0 "); -+#endif - } else { - /* The loader should have set the command line */ - /* too early for panic to do any good */ diff --git a/target/linux/sibyte/patches/102-sbmac_net_device_opts.patch b/target/linux/sibyte/patches/102-sbmac_net_device_opts.patch deleted file mode 100644 index 8171ef367..000000000 --- a/target/linux/sibyte/patches/102-sbmac_net_device_opts.patch +++ /dev/null @@ -1,49 +0,0 @@ ---- a/drivers/net/sb1250-mac.c -+++ b/drivers/net/sb1250-mac.c -@@ -2271,6 +2271,22 @@ static int sb1250_change_mtu(struct net_ - return 0; - } - -+static const struct net_device_ops sbmac_netdev_ops = { -+ .ndo_open = sbmac_open, -+ .ndo_stop = sbmac_close, -+ .ndo_start_xmit = sbmac_start_tx, -+ .ndo_tx_timeout = sbmac_tx_timeout, -+ .ndo_do_ioctl = sbmac_mii_ioctl, -+ .ndo_set_multicast_list = sbmac_set_rx_mode, -+ .ndo_change_mtu = sb1250_change_mtu, -+ .ndo_validate_addr = eth_validate_addr, -+ .ndo_set_mac_address = eth_mac_addr, -+ -+#ifdef CONFIG_NET_POLL_CONTROLLER -+ .ndo_poll_controller = sbmac_netpoll, -+#endif -+}; -+ - /********************************************************************** - * SBMAC_INIT(dev) - * -@@ -2327,21 +2343,12 @@ static int sbmac_init(struct platform_de - - spin_lock_init(&(sc->sbm_lock)); - -- dev->open = sbmac_open; -- dev->hard_start_xmit = sbmac_start_tx; -- dev->stop = sbmac_close; -- dev->set_multicast_list = sbmac_set_rx_mode; -- dev->do_ioctl = sbmac_mii_ioctl; -- dev->tx_timeout = sbmac_tx_timeout; -+ dev->netdev_ops = &sbmac_netdev_ops; -+ - dev->watchdog_timeo = TX_TIMEOUT; - - netif_napi_add(dev, &sc->napi, sbmac_poll, 16); - -- dev->change_mtu = sb1250_change_mtu; --#ifdef CONFIG_NET_POLL_CONTROLLER -- dev->poll_controller = sbmac_netpoll; --#endif -- - dev->irq = UNIT_INT(idx); - - /* This is needed for PASS2 for Rx H/W checksum feature */ diff --git a/target/linux/sibyte/patches/104-sibyte_rtc_cleanup.patch b/target/linux/sibyte/patches/104-sibyte_rtc_cleanup.patch index e4bd8bc7e..f789dada9 100644 --- a/target/linux/sibyte/patches/104-sibyte_rtc_cleanup.patch +++ b/target/linux/sibyte/patches/104-sibyte_rtc_cleanup.patch @@ -1,460 +1,3 @@ ---- a/arch/mips/sibyte/swarm/Makefile -+++ b/arch/mips/sibyte/swarm/Makefile -@@ -1,4 +1,3 @@ --obj-y := platform.o setup.o rtc_xicor1241.o \ -- rtc_m41t81.o -+obj-y := platform.o setup.o - - obj-$(CONFIG_I2C_BOARDINFO) += swarm-i2c.o ---- a/arch/mips/sibyte/swarm/rtc_m41t81.c -+++ /dev/null -@@ -1,233 +0,0 @@ --/* -- * Copyright (C) 2000, 2001 Broadcom Corporation -- * -- * Copyright (C) 2002 MontaVista Software Inc. -- * Author: jsun@mvista.com or jsun@junsun.net -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License as published by the -- * Free Software Foundation; either version 2 of the License, or (at your -- * option) any later version. -- * -- */ --#include --#include --#include -- --#include --#include --#include -- --#include --#include --#include -- -- --/* M41T81 definitions */ -- --/* -- * Register bits -- */ -- --#define M41T81REG_SC_ST 0x80 /* stop bit */ --#define M41T81REG_HR_CB 0x40 /* century bit */ --#define M41T81REG_HR_CEB 0x80 /* century enable bit */ --#define M41T81REG_CTL_S 0x20 /* sign bit */ --#define M41T81REG_CTL_FT 0x40 /* frequency test bit */ --#define M41T81REG_CTL_OUT 0x80 /* output level */ --#define M41T81REG_WD_RB0 0x01 /* watchdog resolution bit 0 */ --#define M41T81REG_WD_RB1 0x02 /* watchdog resolution bit 1 */ --#define M41T81REG_WD_BMB0 0x04 /* watchdog multiplier bit 0 */ --#define M41T81REG_WD_BMB1 0x08 /* watchdog multiplier bit 1 */ --#define M41T81REG_WD_BMB2 0x10 /* watchdog multiplier bit 2 */ --#define M41T81REG_WD_BMB3 0x20 /* watchdog multiplier bit 3 */ --#define M41T81REG_WD_BMB4 0x40 /* watchdog multiplier bit 4 */ --#define M41T81REG_AMO_ABE 0x20 /* alarm in "battery back-up mode" enable bit */ --#define M41T81REG_AMO_SQWE 0x40 /* square wave enable */ --#define M41T81REG_AMO_AFE 0x80 /* alarm flag enable flag */ --#define M41T81REG_ADT_RPT5 0x40 /* alarm repeat mode bit 5 */ --#define M41T81REG_ADT_RPT4 0x80 /* alarm repeat mode bit 4 */ --#define M41T81REG_AHR_RPT3 0x80 /* alarm repeat mode bit 3 */ --#define M41T81REG_AHR_HT 0x40 /* halt update bit */ --#define M41T81REG_AMN_RPT2 0x80 /* alarm repeat mode bit 2 */ --#define M41T81REG_ASC_RPT1 0x80 /* alarm repeat mode bit 1 */ --#define M41T81REG_FLG_AF 0x40 /* alarm flag (read only) */ --#define M41T81REG_FLG_WDF 0x80 /* watchdog flag (read only) */ --#define M41T81REG_SQW_RS0 0x10 /* sqw frequency bit 0 */ --#define M41T81REG_SQW_RS1 0x20 /* sqw frequency bit 1 */ --#define M41T81REG_SQW_RS2 0x40 /* sqw frequency bit 2 */ --#define M41T81REG_SQW_RS3 0x80 /* sqw frequency bit 3 */ -- -- --/* -- * Register numbers -- */ -- --#define M41T81REG_TSC 0x00 /* tenths/hundredths of second */ --#define M41T81REG_SC 0x01 /* seconds */ --#define M41T81REG_MN 0x02 /* minute */ --#define M41T81REG_HR 0x03 /* hour/century */ --#define M41T81REG_DY 0x04 /* day of week */ --#define M41T81REG_DT 0x05 /* date of month */ --#define M41T81REG_MO 0x06 /* month */ --#define M41T81REG_YR 0x07 /* year */ --#define M41T81REG_CTL 0x08 /* control */ --#define M41T81REG_WD 0x09 /* watchdog */ --#define M41T81REG_AMO 0x0A /* alarm: month */ --#define M41T81REG_ADT 0x0B /* alarm: date */ --#define M41T81REG_AHR 0x0C /* alarm: hour */ --#define M41T81REG_AMN 0x0D /* alarm: minute */ --#define M41T81REG_ASC 0x0E /* alarm: second */ --#define M41T81REG_FLG 0x0F /* flags */ --#define M41T81REG_SQW 0x13 /* square wave register */ -- --#define M41T81_CCR_ADDRESS 0x68 -- --#define SMB_CSR(reg) IOADDR(A_SMB_REGISTER(1, reg)) -- --static int m41t81_read(uint8_t addr) --{ -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- __raw_writeq(addr & 0xff, SMB_CSR(R_SMB_CMD)); -- __raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR1BYTE, -- SMB_CSR(R_SMB_START)); -- -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- __raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE, -- SMB_CSR(R_SMB_START)); -- -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { -- /* Clear error bit by writing a 1 */ -- __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); -- return -1; -- } -- -- return (__raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff); --} -- --static int m41t81_write(uint8_t addr, int b) --{ -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- __raw_writeq(addr & 0xff, SMB_CSR(R_SMB_CMD)); -- __raw_writeq(b & 0xff, SMB_CSR(R_SMB_DATA)); -- __raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR2BYTE, -- SMB_CSR(R_SMB_START)); -- -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { -- /* Clear error bit by writing a 1 */ -- __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); -- return -1; -- } -- -- /* read the same byte again to make sure it is written */ -- __raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE, -- SMB_CSR(R_SMB_START)); -- -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- return 0; --} -- --int m41t81_set_time(unsigned long t) --{ -- struct rtc_time tm; -- unsigned long flags; -- -- /* Note we don't care about the century */ -- rtc_time_to_tm(t, &tm); -- -- /* -- * Note the write order matters as it ensures the correctness. -- * When we write sec, 10th sec is clear. It is reasonable to -- * believe we should finish writing min within a second. -- */ -- -- spin_lock_irqsave(&rtc_lock, flags); -- tm.tm_sec = bin2bcd(tm.tm_sec); -- m41t81_write(M41T81REG_SC, tm.tm_sec); -- -- tm.tm_min = bin2bcd(tm.tm_min); -- m41t81_write(M41T81REG_MN, tm.tm_min); -- -- tm.tm_hour = bin2bcd(tm.tm_hour); -- tm.tm_hour = (tm.tm_hour & 0x3f) | (m41t81_read(M41T81REG_HR) & 0xc0); -- m41t81_write(M41T81REG_HR, tm.tm_hour); -- -- /* tm_wday starts from 0 to 6 */ -- if (tm.tm_wday == 0) tm.tm_wday = 7; -- tm.tm_wday = bin2bcd(tm.tm_wday); -- m41t81_write(M41T81REG_DY, tm.tm_wday); -- -- tm.tm_mday = bin2bcd(tm.tm_mday); -- m41t81_write(M41T81REG_DT, tm.tm_mday); -- -- /* tm_mon starts from 0, *ick* */ -- tm.tm_mon ++; -- tm.tm_mon = bin2bcd(tm.tm_mon); -- m41t81_write(M41T81REG_MO, tm.tm_mon); -- -- /* we don't do century, everything is beyond 2000 */ -- tm.tm_year %= 100; -- tm.tm_year = bin2bcd(tm.tm_year); -- m41t81_write(M41T81REG_YR, tm.tm_year); -- spin_unlock_irqrestore(&rtc_lock, flags); -- -- return 0; --} -- --unsigned long m41t81_get_time(void) --{ -- unsigned int year, mon, day, hour, min, sec; -- unsigned long flags; -- -- /* -- * min is valid if two reads of sec are the same. -- */ -- for (;;) { -- spin_lock_irqsave(&rtc_lock, flags); -- sec = m41t81_read(M41T81REG_SC); -- min = m41t81_read(M41T81REG_MN); -- if (sec == m41t81_read(M41T81REG_SC)) break; -- spin_unlock_irqrestore(&rtc_lock, flags); -- } -- hour = m41t81_read(M41T81REG_HR) & 0x3f; -- day = m41t81_read(M41T81REG_DT); -- mon = m41t81_read(M41T81REG_MO); -- year = m41t81_read(M41T81REG_YR); -- spin_unlock_irqrestore(&rtc_lock, flags); -- -- sec = bcd2bin(sec); -- min = bcd2bin(min); -- hour = bcd2bin(hour); -- day = bcd2bin(day); -- mon = bcd2bin(mon); -- year = bcd2bin(year); -- -- year += 2000; -- -- return mktime(year, mon, day, hour, min, sec); --} -- --int m41t81_probe(void) --{ -- unsigned int tmp; -- -- /* enable chip if it is not enabled yet */ -- tmp = m41t81_read(M41T81REG_SC); -- m41t81_write(M41T81REG_SC, tmp & 0x7f); -- -- return (m41t81_read(M41T81REG_SC) != -1); --} ---- a/arch/mips/sibyte/swarm/rtc_xicor1241.c -+++ /dev/null -@@ -1,210 +0,0 @@ --/* -- * Copyright (C) 2000, 2001 Broadcom Corporation -- * -- * Copyright (C) 2002 MontaVista Software Inc. -- * Author: jsun@mvista.com or jsun@junsun.net -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License as published by the -- * Free Software Foundation; either version 2 of the License, or (at your -- * option) any later version. -- */ --#include --#include --#include -- --#include --#include --#include -- --#include --#include --#include -- -- --/* Xicor 1241 definitions */ -- --/* -- * Register bits -- */ -- --#define X1241REG_SR_BAT 0x80 /* currently on battery power */ --#define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */ --#define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */ --#define X1241REG_SR_RTCF 0x01 /* clock failed */ --#define X1241REG_BL_BP2 0x80 /* block protect 2 */ --#define X1241REG_BL_BP1 0x40 /* block protect 1 */ --#define X1241REG_BL_BP0 0x20 /* block protect 0 */ --#define X1241REG_BL_WD1 0x10 --#define X1241REG_BL_WD0 0x08 --#define X1241REG_HR_MIL 0x80 /* military time format */ -- --/* -- * Register numbers -- */ -- --#define X1241REG_BL 0x10 /* block protect bits */ --#define X1241REG_INT 0x11 /* */ --#define X1241REG_SC 0x30 /* Seconds */ --#define X1241REG_MN 0x31 /* Minutes */ --#define X1241REG_HR 0x32 /* Hours */ --#define X1241REG_DT 0x33 /* Day of month */ --#define X1241REG_MO 0x34 /* Month */ --#define X1241REG_YR 0x35 /* Year */ --#define X1241REG_DW 0x36 /* Day of Week */ --#define X1241REG_Y2K 0x37 /* Year 2K */ --#define X1241REG_SR 0x3F /* Status register */ -- --#define X1241_CCR_ADDRESS 0x6F -- --#define SMB_CSR(reg) IOADDR(A_SMB_REGISTER(1, reg)) -- --static int xicor_read(uint8_t addr) --{ -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- __raw_writeq((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD)); -- __raw_writeq(addr & 0xff, SMB_CSR(R_SMB_DATA)); -- __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE, -- SMB_CSR(R_SMB_START)); -- -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE, -- SMB_CSR(R_SMB_START)); -- -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { -- /* Clear error bit by writing a 1 */ -- __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); -- return -1; -- } -- -- return (__raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff); --} -- --static int xicor_write(uint8_t addr, int b) --{ -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- __raw_writeq(addr, SMB_CSR(R_SMB_CMD)); -- __raw_writeq((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA)); -- __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE, -- SMB_CSR(R_SMB_START)); -- -- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) -- ; -- -- if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { -- /* Clear error bit by writing a 1 */ -- __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); -- return -1; -- } else { -- return 0; -- } --} -- --int xicor_set_time(unsigned long t) --{ -- struct rtc_time tm; -- int tmp; -- unsigned long flags; -- -- rtc_time_to_tm(t, &tm); -- tm.tm_year += 1900; -- -- spin_lock_irqsave(&rtc_lock, flags); -- /* unlock writes to the CCR */ -- xicor_write(X1241REG_SR, X1241REG_SR_WEL); -- xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL); -- -- /* trivial ones */ -- tm.tm_sec = bin2bcd(tm.tm_sec); -- xicor_write(X1241REG_SC, tm.tm_sec); -- -- tm.tm_min = bin2bcd(tm.tm_min); -- xicor_write(X1241REG_MN, tm.tm_min); -- -- tm.tm_mday = bin2bcd(tm.tm_mday); -- xicor_write(X1241REG_DT, tm.tm_mday); -- -- /* tm_mon starts from 0, *ick* */ -- tm.tm_mon ++; -- tm.tm_mon = bin2bcd(tm.tm_mon); -- xicor_write(X1241REG_MO, tm.tm_mon); -- -- /* year is split */ -- tmp = tm.tm_year / 100; -- tm.tm_year %= 100; -- xicor_write(X1241REG_YR, tm.tm_year); -- xicor_write(X1241REG_Y2K, tmp); -- -- /* hour is the most tricky one */ -- tmp = xicor_read(X1241REG_HR); -- if (tmp & X1241REG_HR_MIL) { -- /* 24 hour format */ -- tm.tm_hour = bin2bcd(tm.tm_hour); -- tmp = (tmp & ~0x3f) | (tm.tm_hour & 0x3f); -- } else { -- /* 12 hour format, with 0x2 for pm */ -- tmp = tmp & ~0x3f; -- if (tm.tm_hour >= 12) { -- tmp |= 0x20; -- tm.tm_hour -= 12; -- } -- tm.tm_hour = bin2bcd(tm.tm_hour); -- tmp |= tm.tm_hour; -- } -- xicor_write(X1241REG_HR, tmp); -- -- xicor_write(X1241REG_SR, 0); -- spin_unlock_irqrestore(&rtc_lock, flags); -- -- return 0; --} -- --unsigned long xicor_get_time(void) --{ -- unsigned int year, mon, day, hour, min, sec, y2k; -- unsigned long flags; -- -- spin_lock_irqsave(&rtc_lock, flags); -- sec = xicor_read(X1241REG_SC); -- min = xicor_read(X1241REG_MN); -- hour = xicor_read(X1241REG_HR); -- -- if (hour & X1241REG_HR_MIL) { -- hour &= 0x3f; -- } else { -- if (hour & 0x20) -- hour = (hour & 0xf) + 0x12; -- } -- -- day = xicor_read(X1241REG_DT); -- mon = xicor_read(X1241REG_MO); -- year = xicor_read(X1241REG_YR); -- y2k = xicor_read(X1241REG_Y2K); -- spin_unlock_irqrestore(&rtc_lock, flags); -- -- sec = bcd2bin(sec); -- min = bcd2bin(min); -- hour = bcd2bin(hour); -- day = bcd2bin(day); -- mon = bcd2bin(mon); -- year = bcd2bin(year); -- y2k = bcd2bin(y2k); -- -- year += (y2k * 100); -- -- return mktime(year, mon, day, hour, min, sec); --} -- --int xicor_probe(void) --{ -- return (xicor_read(X1241REG_SC) != -1); --} --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c @@ -56,14 +56,6 @@ extern void sb1250_setup(void); @@ -472,7 +15,7 @@ const char *get_system_type(void) { return "SiByte " SIBYTE_BOARD_NAME; -@@ -79,42 +71,14 @@ int swarm_be_handler(struct pt_regs *reg +@@ -79,49 +71,18 @@ int swarm_be_handler(struct pt_regs *reg return (is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL); } @@ -484,20 +27,27 @@ - -enum swarm_rtc_type swarm_rtc_type; - - unsigned long read_persistent_clock(void) + void read_persistent_clock(struct timespec *ts) { + unsigned long sec; + - switch (swarm_rtc_type) { - case RTC_XICOR: -- return xicor_get_time(); +- sec = xicor_get_time(); +- break; - - case RTC_M4LT81: -- return m41t81_get_time(); +- sec = m41t81_get_time(); +- break; - - case RTC_NONE: - default: -- return mktime(2000, 1, 1, 0, 0, 0); +- sec = mktime(2000, 1, 1, 0, 0, 0); +- break; - } -+ return mktime(2000, 1, 1, 0, 0, 0); ++ sec = mktime(2000, 1, 1, 0, 0, 0); + ts->tv_sec = sec; + ts->tv_nsec = 0; } int rtc_mips_set_time(unsigned long sec) @@ -511,13 +61,12 @@ - - case RTC_NONE: - default: -- return -1; + return -1; - } -+ return -1; } void __init plat_mem_setup(void) -@@ -131,11 +95,6 @@ void __init plat_mem_setup(void) +@@ -138,11 +99,6 @@ void __init plat_mem_setup(void) board_be_handler = swarm_be_handler; diff --git a/target/linux/sibyte/patches/105-sibyte_hwmon.patch b/target/linux/sibyte/patches/105-sibyte_hwmon.patch index a5657b97b..93dd4230d 100644 --- a/target/linux/sibyte/patches/105-sibyte_hwmon.patch +++ b/target/linux/sibyte/patches/105-sibyte_hwmon.patch @@ -1,6 +1,6 @@ --- a/arch/mips/sibyte/swarm/swarm-i2c.c +++ b/arch/mips/sibyte/swarm/swarm-i2c.c -@@ -15,6 +15,11 @@ +@@ -13,6 +13,11 @@ #include #include @@ -12,7 +12,7 @@ static struct i2c_board_info swarm_i2c_info1[] __initdata = { { -@@ -26,6 +31,8 @@ static int __init swarm_i2c_init(void) +@@ -24,6 +29,8 @@ static int __init swarm_i2c_init(void) { int err; diff --git a/target/linux/sibyte/patches/106-no_module_reloc.patch b/target/linux/sibyte/patches/106-no_module_reloc.patch index 449bda756..20b707e25 100644 --- a/target/linux/sibyte/patches/106-no_module_reloc.patch +++ b/target/linux/sibyte/patches/106-no_module_reloc.patch @@ -1,7 +1,6 @@ -diff -urN linux-2.6.30.10/arch/mips/Makefile linux-2.6.30.10.new//arch/mips/Makefile ---- linux-2.6.30.10/arch/mips/Makefile 2010-01-29 16:12:01.000000000 +0100 -+++ linux-2.6.30.10.new//arch/mips/Makefile 2009-12-04 07:00:07.000000000 +0100 -@@ -83,7 +83,7 @@ +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -83,7 +83,7 @@ all-$(CONFIG_BOOT_ELF64) := $(vmlinux-64 cflags-y += -G 0 -mno-abicalls -fno-pic -pipe cflags-y += -msoft-float LDFLAGS_vmlinux += -G 0 -static -n -nostdlib @@ -10,10 +9,9 @@ diff -urN linux-2.6.30.10/arch/mips/Makefile linux-2.6.30.10.new//arch/mips/Make cflags-y += -ffreestanding -diff -urN linux-2.6.30.10/arch/mips/include/asm/module.h linux-2.6.30.10.new//arch/mips/include/asm/module.h ---- linux-2.6.30.10/arch/mips/include/asm/module.h 2010-01-29 16:12:01.000000000 +0100 -+++ linux-2.6.30.10.new//arch/mips/include/asm/module.h 2009-12-04 07:00:07.000000000 +0100 -@@ -9,11 +9,6 @@ +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -9,11 +9,6 @@ struct mod_arch_specific { struct list_head dbe_list; const struct exception_table_entry *dbe_start; const struct exception_table_entry *dbe_end; @@ -25,10 +23,9 @@ diff -urN linux-2.6.30.10/arch/mips/include/asm/module.h linux-2.6.30.10.new//ar }; typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ -diff -urN linux-2.6.30.10/arch/mips/kernel/module.c linux-2.6.30.10.new//arch/mips/kernel/module.c ---- linux-2.6.30.10/arch/mips/kernel/module.c 2010-01-29 16:12:01.000000000 +0100 -+++ linux-2.6.30.10.new//arch/mips/kernel/module.c 2009-12-04 07:00:07.000000000 +0100 -@@ -43,116 +43,6 @@ +--- a/arch/mips/kernel/module.c ++++ b/arch/mips/kernel/module.c +@@ -43,117 +43,6 @@ static struct mips_hi16 *mips_hi16_list; static LIST_HEAD(dbe_list); static DEFINE_SPINLOCK(dbe_lock); @@ -141,11 +138,12 @@ diff -urN linux-2.6.30.10/arch/mips/kernel/module.c linux-2.6.30.10.new//arch/mi - for (; page < end; ++page) - __free_page(page); -} +- - void *module_alloc(unsigned long size) { #ifdef MODULE_START -@@ -168,101 +58,23 @@ +@@ -169,99 +58,21 @@ void *module_alloc(unsigned long size) return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL); #else @@ -189,11 +187,8 @@ diff -urN linux-2.6.30.10/arch/mips/kernel/module.c linux-2.6.30.10.new//arch/mi - } else { - vfree(module_region); - } -+ vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ - } - +-} +- -static void *__module_alloc(int size, bool phys) -{ - void *ptr; @@ -211,8 +206,9 @@ diff -urN linux-2.6.30.10/arch/mips/kernel/module.c linux-2.6.30.10.new//arch/mi - kfree(ptr); - else - vfree(ptr); --} -- ++ vfree(module_region); + } + int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { @@ -249,7 +245,7 @@ diff -urN linux-2.6.30.10/arch/mips/kernel/module.c linux-2.6.30.10.new//arch/mi return 0; } -@@ -285,37 +97,27 @@ +@@ -284,36 +95,28 @@ static int apply_r_mips_32_rela(struct m return 0; } @@ -258,7 +254,6 @@ diff -urN linux-2.6.30.10/arch/mips/kernel/module.c linux-2.6.30.10.new//arch/mi +static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) { - unsigned *tramp = start + *plt_offset; -- - *plt_offset += 4 * sizeof(int); - - /* adjust carry for addiu */ @@ -270,7 +265,8 @@ diff -urN linux-2.6.30.10/arch/mips/kernel/module.c linux-2.6.30.10.new//arch/mi - tramp[2] = 0x03200008; /* jr t9 */ - tramp[3] = 0x00000000; /* nop */ + if (v % 4) { -+ printk(KERN_ERR "module %s: dangerous relocation\n", me->name); ++ pr_err("module %s: dangerous R_MIPS_26 REL relocation\n", ++ me->name); + return -ENOEXEC; + } @@ -301,8 +297,8 @@ diff -urN linux-2.6.30.10/arch/mips/kernel/module.c linux-2.6.30.10.new//arch/mi +static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v) { if (v % 4) { - printk(KERN_ERR "module %s: dangerous relocation\n", me->name); -@@ -323,31 +125,17 @@ + pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n", +@@ -322,31 +125,17 @@ static int set_r_mips_26(struct module * } if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { @@ -337,7 +333,7 @@ diff -urN linux-2.6.30.10/arch/mips/kernel/module.c linux-2.6.30.10.new//arch/mi static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v) { struct mips_hi16 *n; -@@ -612,32 +400,11 @@ +@@ -611,32 +400,11 @@ int module_finalize(const Elf_Ehdr *hdr, list_add(&me->arch.dbe_list, &dbe_list); spin_unlock_irq(&dbe_lock); } diff --git a/target/linux/ubicom32/config-2.6.30 b/target/linux/ubicom32/config-default similarity index 100% rename from target/linux/ubicom32/config-2.6.30 rename to target/linux/ubicom32/config-default diff --git a/target/linux/ubicom32/files/arch/ubicom32/Kconfig b/target/linux/ubicom32/files/arch/ubicom32/Kconfig new file mode 100644 index 000000000..acc611630 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/Kconfig @@ -0,0 +1,403 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "uClinux/ubicom32 (w/o MMU) Kernel Configuration" + +config UBICOM32 + bool + select HAVE_OPROFILE + default y + +config RAMKERNEL + bool + default y + +config CPU_BIG_ENDIAN + bool + default y + +config FORCE_MAX_ZONEORDER + int + default "14" + +config HAVE_CLK + bool + default y + +config MMU + bool + default n + +config FPU + bool + default n + +config ZONE_DMA + bool + default y + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + default n + +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + +config GENERIC_FIND_NEXT_BIT + bool + default y + +config GENERIC_GPIO + bool + default y + +config GPIOLIB + bool + default y + +config GENERIC_HWEIGHT + bool + default y + +config GENERIC_HARDIRQS + bool + default y + +config STACKTRACE_SUPPORT + bool + default y + +config LOCKDEP_SUPPORT + bool + default y + +config GENERIC_CALIBRATE_DELAY + bool + default y + +config GENERIC_TIME + bool + default y + +config TIME_LOW_RES + bool + default y + +config GENERIC_CLOCKEVENTS + bool + default y + +config GENERIC_CLOCKEVENTS_BROADCAST + bool + depends on GENERIC_CLOCKEVENTS + default y if SMP && !LOCAL_TIMERS + +config NO_IOPORT + def_bool y + +config ARCH_SUPPORTS_AOUT + def_bool y + +config IRQ_PER_CPU + bool + default y + +config SCHED_NO_NO_OMIT_FRAME_POINTER + bool + default y + +config UBICOM32_PLIO + bool + default n + +menu "Processor type and features" + +comment "Processor type will be selected by Board" + +config UBICOM32_V3 + bool + help + Ubicom IP5xxx series processor support. + +config UBICOM32_V4 + bool + help + Ubicom IP7xxx series processor support. + +comment "Board" +choice + prompt "Board type" + help + Select your board. + +config NOBOARD + bool "No board selected" + help + Default. Don't select any board specific config. Will not build unless you change! + +# Add your boards here +source "arch/ubicom32/mach-ip5k/Kconfig" +source "arch/ubicom32/mach-ip7k/Kconfig" + +endchoice + +comment "Kernel Options" +config SMP + bool "Symmetric multi-processing support" + select USE_GENERIC_SMP_HELPERS + default n + help + Enables multithreading support. Enabling SMP support increases + the size of system data structures. SMP support can have either + positive or negative impact on performance depending on workloads. + + If you do not know what to do here, say N. +config OLD_40400010_SYSTEM_CALL + bool "Provide old system call interface at 0x40400010" + default y + help + Provides the old system call interface, does not affect the + new system_call interface. + +config NR_CPUS + int "Number of configured CPUs" + range 2 32 + default 2 + depends on SMP + help + Upper bound on the number of CPUs. Space is reserved + at compile time for this many CPUs. + +config LOCAL_TIMERS + bool "Use local timer interrupts" + depends on SMP + default y + help + Enable support for local timers on SMP platforms, rather then the + legacy IPI broadcast method. Local timers allows the system + accounting to be spread across the timer interval, preventing a + "thundering herd" at every timer tick. A physical timer is allocated + per cpu. + +config TIMER_EXTRA_ALLOC + int "Number of additional physical timer events to create" + depends on GENERIC_CLOCKEVENTS + default 0 + help + The Ubicom32 processor has a number of event timers that can be wrapped + in Linux clock event structures (assuming that the timers are not being + used for another purpose). Based on the value of LOCAL_TIMERS, either + 2 timers will be used or a timer will be used for every CPU. This value + allows the programmer to select additional timers over that amount. + +config IRQSTACKS + bool "Create separate stacks for interrupt handling" + default n + help + Selecting this causes interrupts to be created on a separate + stack instead of nesting the interrupts on the kernel stack. + +config IRQSTACKS_USEOCM + bool "Use OCM for interrupt stacks" + default n + depends on IRQSTACKS + help + Selecting this cause the interrupt stacks to be placed in OCM + reducing cache misses at the expense of using the OCM for servicing + interrupts. + +menu "OCM Instruction Heap" + +config OCM_MODULES_RESERVATION + int "OCM Instruction heap reservation. 0-192 kB" + range 0 192 + default "0" + help + The minimum amount of OCM memory to reserve for kernel loadable module + code. If you are not using this memory it cannot be used for anything + else. Leave it as 0 if you have prebuilt modules that are compiled with + OCM support. + +config OCM_MODULES_MAY_CONSUME_REMAINING_CODESPACE + bool "Give all unused ocm code space to the ocm instruction heap." + default n + help + Allow the OCM instruction heap allocation to consume any remaining + unused OCM code space. The result of this is that you will not have + and deterministic results, but you will not have any waste either. + +config OCM_MODULES_FALLBACK_TO_DDR + bool "Loadable Modules requiring OCM may fallback to use DDR." + default n + help + If a module cannot get the OCM code it requires allow DDR to + be used instead. +endmenu + +config HZ + int "Frequency of 'jiffies' (for polling)" + default 1000 + help + 100 is common for embedded systems, but 1000 allows + you to do more drivers without actually having + interrupts working properly. + +comment "RAM configuration" + +config MIN_RAMSIZE + hex "Minimum Size of RAM (in bytes)" + range 0x01000000 0x08000000 + default "0x02000000" + help + Define the minimum acceptable size of the system + RAM. Must be at least 16MB (0x01000000) + +comment "Build options" +config LINKER_RELAXATION + bool "Linker Relaxation" + default y + help + Turns on linker relaxation that will produce smaller + faster code. Increases link time. + +comment "Driver options" +menu "PCI Bus" +config PCI + bool "PCI bus" + default true + help + Enable/Disable PCI bus + source "drivers/pci/Kconfig" + + +config PCI_DEV0_IDSEL + hex "slot 0 address" + depends on PCI + default "0x01000000" + help + Slot 0 address. This address should correspond to the address line + which the IDSEL bit for this slot is connected to. + +config PCI_DEV1_IDSEL + hex "slot 1 address" + depends on PCI + default "0x02000000" + help + Slot 1 address. This address should correspond to the address line + which the IDSEL bit for this slot is connected to. +endmenu +# End PCI + +menu "Input devices" +config UBICOM_INPUT + bool "Ubicom polled GPIO input driver" + select INPUT + select INPUT_POLLDEV + help + Polling input driver, much like the GPIO input driver, except that it doesn't + rely on interrupts. It will report events via the input subsystem. + default n + +config UBICOM_INPUT_I2C + bool "Ubicom polled GPIO input driver over I2C" + select INPUT + select INPUT_POLLDEV + help + Polling input driver, much like the PCA953x driver, it can support a variety of + different I2C I/O expanders. This device polls the I2C I/O expander for events + and reports them via the input subsystem. + default n +endmenu +# Input devices + +source "arch/ubicom32/mach-common/Kconfig.switch" + +menu "Misc devices" +config UBICOM_HID + bool "Ubicom HID driver" + select INPUT + select INPUT_POLLDEV + select LCD_CLASS_DEVICE + help + Driver for HID chip found on some Ubicom reference designs. This chip handles + PWM, button input, and IR remote control. It registers as an input device and + a backlight device. + default n +endmenu +# Misc devices + +config CMDLINE_BOOL + bool "Built-in kernel command line" + default n + help + Allow for specifying boot arguments to the kernel at + build time. On some systems (e.g. embedded ones), it is + necessary or convenient to provide some or all of the + kernel boot arguments with the kernel itself (that is, + to not rely on the boot loader to provide them.) + + To compile command line arguments into the kernel, + set this option to 'Y', then fill in the + the boot arguments in CONFIG_CMDLINE. + + Systems with fully functional boot loaders (i.e. non-embedded) + should leave this option set to 'N'. + +config CMDLINE + string "Built-in kernel command string" + depends on CMDLINE_BOOL + default "" + help + Enter arguments here that should be compiled into the kernel + image and used at boot time. If the boot loader provides a + command line at boot time, it is appended to this string to + form the full kernel command line, when the system boots. + + However, you can use the CONFIG_CMDLINE_OVERRIDE option to + change this behavior. + + In most cases, the command line (whether built-in or provided + by the boot loader) should specify the device for the root + file system. + +config CMDLINE_OVERRIDE + bool "Built-in command line overrides boot loader arguments" + default n + depends on CMDLINE_BOOL + help + Set this option to 'Y' to have the kernel ignore the boot loader + command line, and use ONLY the built-in command line. + + This is used to work around broken boot loaders. This should + be set to 'N' under normal conditions. + +endmenu +# End Processor type and features + +source "arch/ubicom32/Kconfig.debug" + +menu "Executable file formats" +source "fs/Kconfig.binfmt" +endmenu + +source "init/Kconfig" +source "kernel/Kconfig.preempt" +source "kernel/time/Kconfig" +source "mm/Kconfig" +source "net/Kconfig" +source "drivers/Kconfig" +source "fs/Kconfig" +source "security/Kconfig" +source "crypto/Kconfig" +source "lib/Kconfig" diff --git a/target/linux/ubicom32/files/arch/ubicom32/Kconfig.debug b/target/linux/ubicom32/files/arch/ubicom32/Kconfig.debug new file mode 100644 index 000000000..330c75806 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/Kconfig.debug @@ -0,0 +1,129 @@ +menu "Kernel hacking" + +config TRACE_IRQFLAGS_SUPPORT + def_bool y + +config DEBUG_VERBOSE + bool "Verbose fault messages" + default y + select PRINTK + help + When a program crashes due to an exception, or the kernel detects + an internal error, the kernel can print a not so brief message + explaining what the problem was. This debugging information is + useful to developers and kernel hackers when tracking down problems, + but mostly meaningless to other people. This is always helpful for + debugging but serves no purpose on a production system. + Most people should say N here. + +config PROTECT_KERNEL + default y + bool 'Enable Kernel range register Protection' + help + Adds code to enable/disable range registers to protect static + kernel code/data from userspace. Currently the ranges covered + do no protect kernel loadable modules or dynamically allocated + kernel data. + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +config EARLY_PRINTK + bool "Use the driver that you selected as console also for early printk (to debug kernel bootup)." + default n + help + If you want to use the serdes driver (console=ttyUS0) for + early printk, you must also supply an additional kernel boot + parameter like this: + + serdes=ioportaddr,irq,clockrate,baud + + For an IP7160RGW eval board, you could use this: + + serdes=0x2004000,61,250000000,57600 + + which will let you see early printk output at 57600 baud. + +config STOP_ON_TRAP + bool "Enable stopping at the LDSR for all traps" + default n + help + Cause the LDSR to stop all threads whenever a trap is about to be serviced + +config STOP_ON_BUG + bool "Enable stopping on failed BUG_ON()" + default n + help + Cause all BUG_ON failures to stop all threads + +config DEBUG_IRQMEASURE + bool "Enable IRQ handler measurements" + default n + help + When enabled each IRQ's min/avg/max times will be printed. If the handler + re-enables interrupt, the times will show the full time including to service + nested interrupts. See /proc/irq_measurements. + +config DEBUG_PCIMEASURE + bool "Enable PCI transaction measurements" + default n + help + When enabled the system will measure the min/avg/max timer for each PCI transactions. + See /proc/pci_measurements. + +config ACCESS_OK_CHECKS_ENABLED + bool "Enable user space access checks" + default n + help + Enabling this check causes the kernel to verify that addresses passed + to the kernel by the user space code are within the processes + address space. On a no-mmu system, this is done by examining the + processes memory data structures (adversly affecting performance) but + ensuring that a process does not ask the kernel to violate another + processes address space. Sadly, the kernel uses access_ok() for + address that are in the kernel which results in a large volume of + false positives. + +choice + prompt "Unaligned Access Support" + default UNALIGNED_ACCESS_ENABLED + help + Kernel / Userspace unaligned access handling. + +config UNALIGNED_ACCESS_ENABLED + bool "Kernel and Userspace" + help + +config UNALIGNED_ACCESS_USERSPACE_ONLY + bool "Userspace Only" + help + +config UNALIGNED_ACCESS_DISABLED + bool "Disabled" + help + +endchoice + +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + default n + depends on DEBUG_KERNEL + help + This option will cause messages to be printed if free kernel stack space + drops below a certain limit (THREAD_SIZE /8). + +config DEBUG_STACK_USAGE + bool "Stack utilization instrumentation" + default n + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free kernel stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +source "lib/Kconfig.debug" + +endmenu diff --git a/target/linux/ubicom32/files/arch/ubicom32/Makefile b/target/linux/ubicom32/files/arch/ubicom32/Makefile new file mode 100644 index 000000000..c5712d8c8 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/Makefile @@ -0,0 +1,104 @@ +# +# arch/ubicom32/Makefile +# +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# + +KBUILD_DEFCONFIG := + +# setup the machine name and machine dependent settings +machine-$(CONFIG_UBICOM32_V3) := ip5k +machine-$(CONFIG_UBICOM32_V4) := ip7k +MACHINE := $(machine-y) +export MACHINE + +model-$(CONFIG_RAMKERNEL) := ram +model-$(CONFIG_ROMKERNEL) := rom +MODEL := $(model-y) +export MODEL + +CPUCLASS := $(cpuclass-y) + +export CPUCLASS + +# +# We want the core kernel built using the fastcall ABI but modules need +# to be built using the slower calling convention because they could be +# loaded out of range for fast calls. +# +CFLAGS_KERNEL += -mfastcall +CFLAGS_MODULE += -mno-fastcall + +# +# Some CFLAG additions based on specific CPU type. +# +cflags-$(CONFIG_UBICOM32_V3) := -march=ubicom32v3 -DIP5000 +cflags-$(CONFIG_UBICOM32_V4) := -march=ubicom32v4 -DIP7000 + +ldflags-$(CONFIG_LINKER_RELAXATION) := --relax +LDFLAGS_vmlinux := $(ldflags-y) + +GCCLIBDIR := $(dir $(shell $(CC) $(cflags-y) -print-libgcc-file-name)) +GCC_LIBS := $(GCCLIBDIR)/libgcc.a + +KBUILD_CFLAGS += $(cflags-y) -ffunction-sections +KBUILD_AFLAGS += $(cflags-y) + +KBUILD_CFLAGS += -D__linux__ -Dlinux +KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\" + +# include any machine specific directory +ifneq ($(machine-y),) +core-y += arch/$(ARCH)/mach-$(MACHINE)/ +endif + +head-y := arch/$(ARCH)/kernel/head.o + +core-y += arch/$(ARCH)/kernel/ \ + arch/$(ARCH)/mm/ \ + arch/$(ARCH)/crypto/ \ + arch/$(ARCH)/mach-common/ + +drivers-$(CONFIG_OPROFILE) += arch/ubicom32/oprofile/ + +libs-y += arch/$(ARCH)/lib/ +libs-y += $(GCC_LIBS) + +archclean: + +# make sure developer has selected a valid board +ifeq ($(CONFIG_NOBOARD),y) +# $(error have to select a valid board file $(CONFIG_NOBOARD), please run kernel config again) +_all: config_board_error +endif + +config_board_error: + @echo "*************************************************" + @echo "You have not selected a proper board." + @echo "Please run menuconfig (or config) against your" + @echo "kernel and choose your board under Processor" + @echo "options" + @echo "*************************************************" + @exit 1 diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/Makefile b/target/linux/ubicom32/files/arch/ubicom32/crypto/Makefile new file mode 100644 index 000000000..2d8e5863c --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/Makefile @@ -0,0 +1,36 @@ +# +# arch/ubicom32/crypto/Makefile +# +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# +obj-$(CONFIG_CRYPTO_UBICOM32) += crypto_ubicom32.o +obj-$(CONFIG_CRYPTO_AES_UBICOM32) += aes_ubicom32.o +obj-$(CONFIG_CRYPTO_DES_UBICOM32) += des.o +obj-$(CONFIG_CRYPTO_MD5_UBICOM32) += md5.o +obj-$(CONFIG_CRYPTO_SHA1_UBICOM32) += sha1.o + +des-y := des_ubicom32.o des_check_key.o +md5-y := md5_ubicom32.o md5_ubicom32_asm.o +sha1-y := sha1_ubicom32.o diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/aes_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/aes_ubicom32.c new file mode 100644 index 000000000..f0b9f86bc --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/aes_ubicom32.c @@ -0,0 +1,458 @@ +/* + * arch/ubicom32/crypto/aes_ubicom32.c + * Ubicom32 implementation of the AES Cipher Algorithm. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include "crypto_ubicom32.h" +#include + +struct ubicom32_aes_ctx { + u8 key[AES_MAX_KEY_SIZE]; + u32 ctrl; + int key_len; +}; + +static inline void aes_hw_set_key(const u8 *key, u8 key_len) +{ + /* + * switch case has more overhead than 4 move.4 instructions, so just copy 256 bits + */ + SEC_SET_KEY_256(key); +} + +static inline void aes_hw_set_iv(const u8 *iv) +{ + SEC_SET_IV_4W(iv); +} + +static inline void aes_hw_cipher(u8 *out, const u8 *in) +{ + SEC_SET_INPUT_4W(in); + + asm volatile ( + " ; start AES by writing 0x40(SECURITY_BASE) \n\t" + " move.4 0x40(%0), #0x01 \n\t" + " pipe_flush 0 \n\t" + " \n\t" + " ; wait for the module to calculate the output \n\t" + " btst 0x04(%0), #0 \n\t" + " jmpne.f .-4 \n\t" + : + : "a" (SEC_BASE) + : "cc" + ); + + SEC_GET_OUTPUT_4W(out); +} + +static int __ocm_text aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm); + + uctx->key_len = key_len; + memcpy(uctx->key, in_key, key_len); + + /* + * leave out HASH_ALG (none = 0), CBC (no = 0), DIR (unknown) yet + */ + switch (uctx->key_len) { + case 16: + uctx->ctrl = SEC_KEY_128_BITS | SEC_ALG_AES; + break; + case 24: + uctx->ctrl = SEC_KEY_192_BITS | SEC_ALG_AES; + break; + case 32: + uctx->ctrl = SEC_KEY_256_BITS | SEC_ALG_AES; + break; + } + + return 0; +} + +static inline void aes_cipher(struct crypto_tfm *tfm, u8 *out, const u8 *in, u32 extra_flags) +{ + const struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm); + + hw_crypto_lock(); + hw_crypto_check(); + hw_crypto_set_ctrl(uctx->ctrl | extra_flags); + + aes_hw_set_key(uctx->key, uctx->key_len); + aes_hw_cipher(out, in); + + hw_crypto_unlock(); +} + +static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + aes_cipher(tfm, out, in, SEC_DIR_ENCRYPT); +} + +static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + aes_cipher(tfm, out, in, SEC_DIR_DECRYPT); +} + +static struct crypto_alg aes_alg = { + .cra_name = "aes", + .cra_driver_name = "aes-ubicom32", + .cra_priority = CRYPTO_UBICOM32_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_aes_ctx), + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt, + } + } +}; + +static void __ocm_text ecb_aes_crypt_loop(u8 *out, u8 *in, unsigned int n) +{ + while (likely(n)) { + aes_hw_cipher(out, in); + out += AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + n -= AES_BLOCK_SIZE; + } +} + +static int __ocm_text ecb_aes_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes, u32 extra_flags) +{ + const struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm); + int ret; + + struct blkcipher_walk walk; + blkcipher_walk_init(&walk, dst, src, nbytes); + ret = blkcipher_walk_virt(desc, &walk); + if (ret) { + return ret; + } + + hw_crypto_lock(); + hw_crypto_check(); + + hw_crypto_set_ctrl(uctx->ctrl | extra_flags); + aes_hw_set_key(uctx->key, uctx->key_len); + + while (likely((nbytes = walk.nbytes))) { + /* only use complete blocks */ + unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1); + u8 *out = walk.dst.virt.addr; + u8 *in = walk.src.virt.addr; + + /* finish n/16 blocks */ + ecb_aes_crypt_loop(out, in, n); + + nbytes &= AES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, &walk, nbytes); + } + + hw_crypto_unlock(); + return ret; +} + +static int ecb_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT); +} + +static int ecb_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT); +} + +static struct crypto_alg ecb_aes_alg = { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-ubicom32", + .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_aes_ctx), + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = aes_set_key, + .encrypt = ecb_aes_encrypt, + .decrypt = ecb_aes_decrypt, + } + } +}; + +#if CRYPTO_UBICOM32_LOOP_ASM +void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + asm volatile ( + "; set init. iv 4w \n\t" + " move.4 0x50(%0), 0x0(%3) \n\t" + " move.4 0x54(%0), 0x4(%3) \n\t" + " move.4 0x58(%0), 0x8(%3) \n\t" + " move.4 0x5c(%0), 0xc(%3) \n\t" + " \n\t" + "; we know n > 0, so we can always \n\t" + "; load the first block \n\t" + "; set input 4w \n\t" + " move.4 0x30(%0), 0x0(%2) \n\t" + " move.4 0x34(%0), 0x4(%2) \n\t" + " move.4 0x38(%0), 0x8(%2) \n\t" + " move.4 0x3c(%0), 0xc(%2) \n\t" + " \n\t" + "; kickoff hw \n\t" + " move.4 0x40(%0), %2 \n\t" + " \n\t" + "; update n & flush \n\t" + " add.4 %4, #-16, %4 \n\t" + " pipe_flush 0 \n\t" + " \n\t" + "; while (n): work on 2nd block \n\t" + " 1: lsl.4 d15, %4, #0x0 \n\t" + " jmpeq.f 5f \n\t" + " \n\t" + "; set input 4w (2nd) \n\t" + " move.4 0x30(%0), 0x10(%2) \n\t" + " move.4 0x34(%0), 0x14(%2) \n\t" + " move.4 0x38(%0), 0x18(%2) \n\t" + " move.4 0x3c(%0), 0x1c(%2) \n\t" + " \n\t" + "; update n/in asap while waiting \n\t" + " add.4 %4, #-16, %4 \n\t" + " move.4 d15, 16(%2)++ \n\t" + " \n\t" + "; wait for the previous output \n\t" + " btst 0x04(%0), #0 \n\t" + " jmpne.f -4 \n\t" + " \n\t" + "; read previous output \n\t" + " move.4 0x0(%1), 0x50(%0) \n\t" + " move.4 0x4(%1), 0x54(%0) \n\t" + " move.4 0x8(%1), 0x58(%0) \n\t" + " move.4 0xc(%1), 0x5c(%0) \n\t" + " \n\t" + "; kick off hw for 2nd input \n\t" + " move.4 0x40(%0), %2 \n\t" + " \n\t" + "; update out asap \n\t" + " move.4 d15, 16(%1)++ \n\t" + " \n\t" + "; go back to loop \n\t" + " jmpt 1b \n\t" + " \n\t" + "; wait for last output \n\t" + " 5: btst 0x04(%0), #0 \n\t" + " jmpne.f -4 \n\t" + " \n\t" + "; read last output \n\t" + " move.4 0x0(%1), 0x50(%0) \n\t" + " move.4 0x4(%1), 0x54(%0) \n\t" + " move.4 0x8(%1), 0x58(%0) \n\t" + " move.4 0xc(%1), 0x5c(%0) \n\t" + " \n\t" + "; copy out iv \n\t" + " move.4 0x0(%3), 0x50(%0) \n\t" + " move.4 0x4(%3), 0x54(%0) \n\t" + " move.4 0x8(%3), 0x58(%0) \n\t" + " move.4 0xc(%3), 0x5c(%0) \n\t" + " \n\t" + : + : "a" (SEC_BASE), "a" (out), "a" (in), "a" (iv), "d" (n) + : "d15", "cc" + ); +} + +#else + +static void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + aes_hw_set_iv(iv); + while (likely(n)) { + aes_hw_cipher(out, in); + out += AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + n -= AES_BLOCK_SIZE; + } + SEC_COPY_4W(iv, out - AES_BLOCK_SIZE); +} + +#endif + +static void __ocm_text cbc_aes_decrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + while (likely(n)) { + aes_hw_set_iv(iv); + SEC_COPY_4W(iv, in); + aes_hw_cipher(out, in); + out += AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + n -= AES_BLOCK_SIZE; + } +} + +static int __ocm_text cbc_aes_crypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes, u32 extra_flags) +{ + struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm); + int ret; + + struct blkcipher_walk walk; + blkcipher_walk_init(&walk, dst, src, nbytes); + ret = blkcipher_walk_virt(desc, &walk); + if (unlikely(ret)) { + return ret; + } + + hw_crypto_lock(); + hw_crypto_check(); + + hw_crypto_set_ctrl(uctx->ctrl | extra_flags); + aes_hw_set_key(uctx->key, uctx->key_len); + + while (likely((nbytes = walk.nbytes))) { + /* only use complete blocks */ + unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1); + if (likely(n)) { + u8 *out = walk.dst.virt.addr; + u8 *in = walk.src.virt.addr; + + if (extra_flags & SEC_DIR_ENCRYPT) { + cbc_aes_encrypt_loop(out, in, walk.iv, n); + } else { + cbc_aes_decrypt_loop(out, in, walk.iv, n); + } + } + + nbytes &= AES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, &walk, nbytes); + } + hw_crypto_unlock(); + + return ret; +} + +static int __ocm_text cbc_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT | SEC_CBC_SET); +} + +static int __ocm_text cbc_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT | SEC_CBC_SET); +} + +static struct crypto_alg cbc_aes_alg = { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-ubicom32", + .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_aes_ctx), + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = aes_set_key, + .encrypt = cbc_aes_encrypt, + .decrypt = cbc_aes_decrypt, + } + } +}; + +static int __init aes_init(void) +{ + int ret; + + hw_crypto_init(); + + ret = crypto_register_alg(&aes_alg); + if (ret) + goto aes_err; + + ret = crypto_register_alg(&ecb_aes_alg); + if (ret) + goto ecb_aes_err; + + ret = crypto_register_alg(&cbc_aes_alg); + if (ret) + goto cbc_aes_err; + +out: + return ret; + +cbc_aes_err: + crypto_unregister_alg(&ecb_aes_alg); +ecb_aes_err: + crypto_unregister_alg(&aes_alg); +aes_err: + goto out; +} + +static void __exit aes_fini(void) +{ + crypto_unregister_alg(&cbc_aes_alg); + crypto_unregister_alg(&ecb_aes_alg); + crypto_unregister_alg(&aes_alg); +} + +module_init(aes_init); +module_exit(aes_fini); + +MODULE_ALIAS("aes"); + +MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_des.h b/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_des.h new file mode 100644 index 000000000..3fc0ac361 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_des.h @@ -0,0 +1,34 @@ +/* + * arch/ubicom32/crypto/crypto_des.h + * Function for checking keys for the DES and Triple DES Encryption + * algorithms. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef __CRYPTO_DES_H__ +#define __CRYPTO_DES_H__ + +extern int crypto_des_check_key(const u8*, unsigned int, u32*); + +#endif /* __CRYPTO_DES_H__ */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.c new file mode 100644 index 000000000..237ebbd9f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.c @@ -0,0 +1,50 @@ +/* + * arch/ubicom32/crypto/crypto_ubicom32.c + * Generic code to support ubicom32 hardware crypto accelerator + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include "crypto_ubicom32.h" + +spinlock_t crypto_ubicom32_lock; +bool crypto_ubicom32_inited = false; +volatile bool crypto_ubicom32_on = false; +volatile unsigned long crypto_ubicom32_last_use; + +struct timer_list crypto_ubicom32_ps_timer; +void crypto_ubicom32_ps_check(unsigned long data) +{ + unsigned long idle_time = msecs_to_jiffies(HW_CRYPTO_PS_MAX_IDLE_MS); + + BUG_ON(!crypto_ubicom32_on); + + if (((jiffies - crypto_ubicom32_last_use) > idle_time) && spin_trylock_bh(&crypto_ubicom32_lock)) { + hw_crypto_turn_off(); + spin_unlock_bh(&crypto_ubicom32_lock); + return; + } + + /* keep monitoring */ + hw_crypto_ps_start(); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.h b/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.h new file mode 100644 index 000000000..e754c19b9 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.h @@ -0,0 +1,346 @@ +/* + * arch/ubicom32/crypto/crypto_ubicom32.h + * Support for Ubicom32 cryptographic instructions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _CRYPTO_ARCH_UBICOM32_CRYPT_H +#define _CRYPTO_ARCH_UBICOM32_CRYPT_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CRYPTO_UBICOM32_LOOP_ASM 1 +#define CRYPTO_UBICOM32_ALIGNMENT 4 +#define SEC_ALIGNED(p) (((u32)p & 3) == 0) + +#define SEC_BASE SECURITY_BASE +#define SEC_KEY_OFFSET SECURITY_KEY_VALUE(0) +#define SEC_INPUT_OFFSET SECURITY_KEY_IN(0) +#define SEC_OUTPUT_OFFSET SECURITY_KEY_OUT(0) +#define SEC_HASH_OFFSET SECURITY_KEY_HASH(0) + +#define SEC_KEY_128_BITS SECURITY_CTRL_KEY_SIZE(0) +#define SEC_KEY_192_BITS SECURITY_CTRL_KEY_SIZE(1) +#define SEC_KEY_256_BITS SECURITY_CTRL_KEY_SIZE(2) + +#define SEC_HASH_NONE SECURITY_CTRL_HASH_ALG_NONE +#define SEC_HASH_MD5 SECURITY_CTRL_HASH_ALG_MD5 +#define SEC_HASH_SHA1 SECURITY_CTRL_HASH_ALG_SHA1 + +#define SEC_CBC_SET SECURITY_CTRL_CBC +#define SEC_CBC_NONE 0 + +#define SEC_ALG_AES SECURITY_CTRL_CIPHER_ALG_AES +#define SEC_ALG_NONE SECURITY_CTRL_CIPHER_ALG_NONE +#define SEC_ALG_DES SECURITY_CTRL_CIPHER_ALG_DES +#define SEC_ALG_3DES SECURITY_CTRL_CIPHER_ALG_3DES + +#define SEC_DIR_ENCRYPT SECURITY_CTRL_ENCIPHER +#define SEC_DIR_DECRYPT 0 + +#define CRYPTO_UBICOM32_PRIORITY 300 +#define CRYPTO_UBICOM32_COMPOSITE_PRIORITY 400 + +#define HW_CRYPTO_PS_MAX_IDLE_MS 100 /* idle time (ms) before shuting down sm */ + +extern spinlock_t crypto_ubicom32_lock; +extern bool crypto_ubicom32_inited; +extern volatile bool crypto_ubicom32_on; +extern volatile unsigned long crypto_ubicom32_last_use; +extern struct timer_list crypto_ubicom32_ps_timer; +extern void crypto_ubicom32_ps_check(unsigned long data); + +#define SEC_COPY_2W(t, s) \ + asm volatile ( \ + " move.4 0(%0), 0(%1) \n\t" \ + " move.4 4(%0), 4(%1) \n\t" \ + \ + : \ + : "a" (t), "a" (s) \ + ) + +#define SEC_COPY_4W(t, s) \ + asm volatile ( \ + " move.4 0(%0), 0(%1) \n\t" \ + " move.4 4(%0), 4(%1) \n\t" \ + " move.4 8(%0), 8(%1) \n\t" \ + " move.4 12(%0), 12(%1) \n\t" \ + : \ + : "a" (t), "a" (s) \ + ) + +#define SEC_COPY_5W(t, s) \ + asm volatile ( \ + " move.4 0(%0), 0(%1) \n\t" \ + " move.4 4(%0), 4(%1) \n\t" \ + " move.4 8(%0), 8(%1) \n\t" \ + " move.4 12(%0), 12(%1) \n\t" \ + " move.4 16(%0), 16(%1) \n\t" \ + : \ + : "a" (t), "a" (s) \ + ) + +#define SEC_SET_KEY_2W(x) \ + asm volatile ( \ + " ; write key to Security Keyblock \n\t" \ + " move.4 0x10(%0), 0(%1) \n\t" \ + " move.4 0x14(%0), 4(%1) \n\t" \ + : \ + : "a" (SECURITY_BASE), "a" (x) \ + ) + +#define SEC_SET_KEY_4W(x) \ + asm volatile ( \ + " ; write key to Security Keyblock \n\t" \ + " move.4 0x10(%0), 0(%1) \n\t" \ + " move.4 0x14(%0), 4(%1) \n\t" \ + " move.4 0x18(%0), 8(%1) \n\t" \ + " move.4 0x1c(%0), 12(%1) \n\t" \ + : \ + : "a"(SECURITY_BASE), "a"(x) \ + ) + +#define SEC_SET_KEY_6W(x) \ + asm volatile ( \ + " ; write key to Security Keyblock \n\t" \ + " move.4 0x10(%0), 0(%1) \n\t" \ + " move.4 0x14(%0), 4(%1) \n\t" \ + " move.4 0x18(%0), 8(%1) \n\t" \ + " move.4 0x1c(%0), 12(%1) \n\t" \ + " move.4 0x20(%0), 16(%1) \n\t" \ + " move.4 0x24(%0), 20(%1) \n\t" \ + : \ + : "a" (SECURITY_BASE), "a" (x) \ + ) + +#define SEC_SET_KEY_8W(x) \ + asm volatile ( \ + " ; write key to Security Keyblock \n\t" \ + " move.4 0x10(%0), 0(%1) \n\t" \ + " move.4 0x14(%0), 4(%1) \n\t" \ + " move.4 0x18(%0), 8(%1) \n\t" \ + " move.4 0x1c(%0), 12(%1) \n\t" \ + " move.4 0x20(%0), 16(%1) \n\t" \ + " move.4 0x24(%0), 20(%1) \n\t" \ + " move.4 0x28(%0), 24(%1) \n\t" \ + " move.4 0x2c(%0), 28(%1) \n\t" \ + : \ + : "a" (SECURITY_BASE), "a" (x) \ + ) + +#define SEC_SET_KEY_64(k) SEC_SET_KEY_2W(k) +#define SEC_SET_KEY_128(k) SEC_SET_KEY_4W(k) +#define SEC_SET_KEY_192(k) SEC_SET_KEY_6W(k) +#define SEC_SET_KEY_256(k) SEC_SET_KEY_8W(k) + +#define DES_SET_KEY(x) SEC_SET_KEY_64(x) +#define DES3_SET_KEY(x) SEC_SET_KEY_192(x) + +#define SEC_SET_INPUT_2W(x) \ + asm volatile ( \ + " ; write key to Security Keyblock \n\t" \ + " move.4 0x30(%0), 0(%1) \n\t" \ + " move.4 0x34(%0), 4(%1) \n\t" \ + : \ + : "a" (SECURITY_BASE), "a" (x) \ + ) + +#define SEC_GET_OUTPUT_2W(x) \ + asm volatile ( \ + " ; write key to Security Keyblock \n\t" \ + " move.4 0(%1), 0x50(%0) \n\t" \ + " move.4 4(%1), 0x54(%0) \n\t" \ + : \ + : "a" (SECURITY_BASE), "a" (x) \ + ) + +#define SEC_SET_INPUT_4W(x) \ + asm volatile ( \ + " ; write key to Security Keyblock \n\t" \ + " move.4 0x30(%0), 0(%1) \n\t" \ + " move.4 0x34(%0), 4(%1) \n\t" \ + " move.4 0x38(%0), 8(%1) \n\t" \ + " move.4 0x3c(%0), 12(%1) \n\t" \ + : \ + : "a" (SECURITY_BASE), "a" (x) \ + ) + +#define SEC_GET_OUTPUT_4W(x) \ + asm volatile ( \ + " ; read output from Security Keyblock \n\t" \ + " move.4 0(%1), 0x50(%0) \n\t" \ + " move.4 4(%1), 0x54(%0) \n\t" \ + " move.4 8(%1), 0x58(%0) \n\t" \ + " move.4 12(%1), 0x5c(%0) \n\t" \ + : \ + : "a" (SECURITY_BASE), "a" (x) \ + ) + +#define SEC_SET_IV_4W(x) \ + asm volatile ( \ + " ; write IV to Security Keyblock \n\t" \ + " move.4 0x50(%0), 0(%1) \n\t" \ + " move.4 0x54(%0), 4(%1) \n\t" \ + " move.4 0x58(%0), 8(%1) \n\t" \ + " move.4 0x5c(%0), 12(%1) \n\t" \ + : \ + : "a" (SECURITY_BASE), "a" (x) \ + ) + +#define SEC_PIPE_FLUSH() asm volatile ( " pipe_flush 0 \n\t" ) + +static inline void hw_crypto_set_ctrl(uint32_t c) +{ + asm volatile ( + " move.4 0(%0), %1 \n\t" + : + : "a" (SECURITY_BASE + SECURITY_CTRL), "d" (c) + ); +} + +static inline void hw_crypto_ps_start(void) +{ + crypto_ubicom32_ps_timer.expires = jiffies + msecs_to_jiffies(HW_CRYPTO_PS_MAX_IDLE_MS >> 1); + add_timer(&crypto_ubicom32_ps_timer); +} + +static inline void hw_crypto_turn_on(void) +{ + asm volatile ( + " moveai A4, %0 \n\t" + " bset 0x0(A4), 0x0(A4), %1 \n\t" + " cycles 11 \n\t" + : + : "i" (OCP_BASE >> 7), "i" (GEN_CLK_PLL_SECURITY_BIT_NO) + : "a4", "cc" + ); + crypto_ubicom32_on = true; +} + +static inline void hw_crypto_turn_off(void) +{ + asm volatile ( + " moveai A4, %0 \n\t" + " bclr 0x0(A4), 0x0(A4), %1 \n\t" + : + : "i" (OCP_BASE >> 7), "i" (GEN_CLK_PLL_SECURITY_BIT_NO) + : "a4", "cc" + ); + crypto_ubicom32_on = false; +} + +/* + * hw_crypto_check + * Most probably hw crypto is called in clusters and it makes no sense to turn it off + * and on and waster 13 cycles every time. + */ +static inline void hw_crypto_check(void) +{ + if (likely(crypto_ubicom32_on)) { + return; + } + crypto_ubicom32_last_use = jiffies; + hw_crypto_turn_on(); + hw_crypto_ps_start(); +} + +/* + * hw_crypto_ps_init + * Init power save timer + */ +static inline void hw_crypto_ps_init(void) +{ + init_timer_deferrable(&crypto_ubicom32_ps_timer); + crypto_ubicom32_ps_timer.function = crypto_ubicom32_ps_check; + crypto_ubicom32_ps_timer.data = 0; +} + +/* + * hw_crypto_init() + * Initialize OCP security module lock and disables its clock. + */ +static inline void hw_crypto_init(void) +{ + if (!crypto_ubicom32_inited) { + crypto_ubicom32_inited = true; + spin_lock_init(&crypto_ubicom32_lock); + hw_crypto_ps_init(); + hw_crypto_turn_off(); + } +} + +/* + * hw_crypto_lock() + * Locks the OCP security module and enables its clock. + */ +static inline void hw_crypto_lock(void) +{ + spin_lock_bh(&crypto_ubicom32_lock); +} + +/* + * hw_crypto_unlock() + * Unlocks the OCP security module and disables its clock. + */ +static inline void hw_crypto_unlock(void) +{ + crypto_ubicom32_last_use = jiffies; + spin_unlock_bh(&crypto_ubicom32_lock); +} + +#define CONFIG_CRYPTO_UBICOM32_DEBUG 1 + +#ifdef CONFIG_CRYPTO_UBICOM32_DEBUG +static inline void hex_dump(void *buf, int b_size, const char *msg) +{ + u8 *b = (u8 *)buf; + int i; + if (msg) { + printk("%s:\t", msg); + } + + for (i=0; i < b_size; i++) { + printk("%02x ", b[i]); + if ((i & 3) == 3) { + printk(" "); + } + if ((i & 31) == 31) { + printk("\n"); + } + } + printk("\n"); +} +#define UBICOM32_SEC_DUMP(a, b, c) hex_dump(a, b, c) +#else +#define UBICOM32_SEC_DUMP(a, b, c) +#endif + +#endif /* _CRYPTO_ARCH_UBICOM32_CRYPT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/des_check_key.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/des_check_key.c new file mode 100644 index 000000000..162e52477 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/des_check_key.c @@ -0,0 +1,148 @@ +/* + * arch/ubicom32/crypto/des_check_key.c + * Ubicom32 architecture function for checking keys for the DES and + * Tripple DES Encryption algorithms. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * Originally released as descore by Dana L. How . + * Modified by Raimar Falke for the Linux-Kernel. + * Derived from Cryptoapi and Nettle implementations, adapted for in-place + * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL. + * + * s390 Version: + * Copyright IBM Corp. 2003 + * Author(s): Thomas Spatzier + * Jan Glauber (jan.glauber@de.ibm.com) + * + * Derived from "crypto/des.c" + * Copyright (c) 1992 Dana L. How. + * Copyright (c) Raimar Falke + * Copyright (c) Gisle Sflensminde + * Copyright (C) 2001 Niels Mvller. + * Copyright (c) 2002 James Morris + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include "crypto_des.h" + +#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o)) + +static const u8 parity[] = { + 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8, +}; + +/* + * RFC2451: Weak key checks SHOULD be performed. + */ +int +crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags) +{ + u32 n, w; + + n = parity[key[0]]; n <<= 4; + n |= parity[key[1]]; n <<= 4; + n |= parity[key[2]]; n <<= 4; + n |= parity[key[3]]; n <<= 4; + n |= parity[key[4]]; n <<= 4; + n |= parity[key[5]]; n <<= 4; + n |= parity[key[6]]; n <<= 4; + n |= parity[key[7]]; + w = 0x88888888L; + + if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY) + && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */ + if (n < 0x41415151) { + if (n < 0x31312121) { + if (n < 0x14141515) { + /* 01 01 01 01 01 01 01 01 */ + if (n == 0x11111111) goto weak; + /* 01 1F 01 1F 01 0E 01 0E */ + if (n == 0x13131212) goto weak; + } else { + /* 01 E0 01 E0 01 F1 01 F1 */ + if (n == 0x14141515) goto weak; + /* 01 FE 01 FE 01 FE 01 FE */ + if (n == 0x16161616) goto weak; + } + } else { + if (n < 0x34342525) { + /* 1F 01 1F 01 0E 01 0E 01 */ + if (n == 0x31312121) goto weak; + /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */ + if (n == 0x33332222) goto weak; + } else { + /* 1F E0 1F E0 0E F1 0E F1 */ + if (n == 0x34342525) goto weak; + /* 1F FE 1F FE 0E FE 0E FE */ + if (n == 0x36362626) goto weak; + } + } + } else { + if (n < 0x61616161) { + if (n < 0x44445555) { + /* E0 01 E0 01 F1 01 F1 01 */ + if (n == 0x41415151) goto weak; + /* E0 1F E0 1F F1 0E F1 0E */ + if (n == 0x43435252) goto weak; + } else { + /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */ + if (n == 0x44445555) goto weak; + /* E0 FE E0 FE F1 FE F1 FE */ + if (n == 0x46465656) goto weak; + } + } else { + if (n < 0x64646565) { + /* FE 01 FE 01 FE 01 FE 01 */ + if (n == 0x61616161) goto weak; + /* FE 1F FE 1F FE 0E FE 0E */ + if (n == 0x63636262) goto weak; + } else { + /* FE E0 FE E0 FE F1 FE F1 */ + if (n == 0x64646565) goto weak; + /* FE FE FE FE FE FE FE FE */ + if (n == 0x66666666) goto weak; + } + } + } + } + return 0; +weak: + *flags |= CRYPTO_TFM_RES_WEAK_KEY; + return -EINVAL; +} + +EXPORT_SYMBOL(crypto_des_check_key); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Key Check function for DES & DES3 Cipher Algorithms"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/des_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/des_ubicom32.c new file mode 100644 index 000000000..14e5fb24e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/des_ubicom32.c @@ -0,0 +1,761 @@ +/* + * arch/ubicom32/crypto/des_ubicom32.c + * Ubicom32 implementation of the DES Cipher Algorithm. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include + +#include "crypto_ubicom32.h" +extern int crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags); + +#define DES_BLOCK_SIZE 8 +#define DES_KEY_SIZE 8 + +#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_192_BLOCK_SIZE DES_BLOCK_SIZE + +#define DES3_SUB_KEY(key, i) (((u8 *)key) + (i * DES_KEY_SIZE)) + +enum des_ops { + DES_ENCRYPT, + DES_DECRYPT, + + DES3_EDE_ENCRYPT, + DES3_EDE_DECRYPT, + +#ifdef DES3_EEE + DES3_EEE_ENCRYPT, + DES3_EEE_DECRYPT, +#endif +}; + +struct ubicom32_des_ctx { + u8 key[3 * DES_KEY_SIZE]; + u32 ctrl; + int key_len; +}; + +static inline void des_hw_set_key(const u8 *key, u8 key_len) +{ + /* + * HW 3DES is not tested yet, use DES just as ipOS + */ + DES_SET_KEY(key); +} + +static inline void des_hw_cipher(u8 *out, const u8 *in) +{ + SEC_SET_INPUT_2W(in); + + asm volatile ( + " ; start DES by writing 0x38(SECURITY_BASE) \n\t" + " move.4 0x38(%0), #0x01 \n\t" + " pipe_flush 0 \n\t" + " \n\t" + " ; wait for the module to calculate the output \n\t" + " btst 0x04(%0), #0 \n\t" + " jmpne.f .-4 \n\t" + : + : "a" (SEC_BASE) + : "cc" + ); + + SEC_GET_OUTPUT_2W(out); +} + + +static void inline des3_hw_ede_encrypt(u8 *keys, u8 *out, const u8 *in) +{ + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 0), DES_KEY_SIZE); + des_hw_cipher(out, in); + + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 1), DES_KEY_SIZE); + des_hw_cipher(out, out); + + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 2), DES_KEY_SIZE); + des_hw_cipher(out, out); +} + +static void inline des3_hw_ede_decrypt(u8 *keys, u8 *out, const u8 *in) +{ + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 2), DES_KEY_SIZE); + des_hw_cipher(out, in); + + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 1), DES_KEY_SIZE); + des_hw_cipher(out, out); + + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 0), DES_KEY_SIZE); + des_hw_cipher(out, out); +} + +#ifdef DES3_EEE +static void inline des3_hw_eee_encrypt(u8 *keys, u8 *out, const u8 *in) +{ + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 0), 2); + des_hw_cipher(out, in); + + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 1), 2); + des_hw_cipher(out, out); + + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 2), 2); + des_hw_cipher(out, out); +} + +static void inline des3_hw_eee_decrypt(u8 *keys, u8 *out, const u8 *in) +{ + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 2), 2); + des_hw_cipher(out, in); + + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 1), 2); + des_hw_cipher(out, out); + + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); + des_hw_set_key(DES3_SUB_KEY(keys, 0), 2); + des_hw_cipher(out, out); +} +#endif + +static int des_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct ubicom32_des_ctx *dctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + int ret; + + /* test if key is valid (not a weak key) */ + ret = crypto_des_check_key(key, keylen, flags); + if (ret == 0) { + memcpy(dctx->key, key, keylen); + dctx->key_len = keylen; + //dctx->ctrl = (keylen == DES_KEY_SIZE) ? SEC_ALG_DES : SEC_ALG_3DES + /* 2DES and 3DES are both implemented with DES hw function */ + dctx->ctrl = SEC_ALG_DES; + } + return ret; +} + +static inline void des_cipher_1b(struct crypto_tfm *tfm, u8 *out, const u8 *in, u32 extra_flags) +{ + const struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm); + + hw_crypto_lock(); + hw_crypto_check(); + hw_crypto_set_ctrl(uctx->ctrl | extra_flags); + + des_hw_set_key(uctx->key, uctx->key_len); + des_hw_cipher(out, in); + + hw_crypto_unlock(); +} + +static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + des_cipher_1b(tfm, out, in, SEC_DIR_ENCRYPT); +} + +static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + des_cipher_1b(tfm, out, in, SEC_DIR_DECRYPT); +} + +static struct crypto_alg des_alg = { + .cra_name = "des", + .cra_driver_name = "des-ubicom32", + .cra_priority = CRYPTO_UBICOM32_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_des_ctx), + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = DES_KEY_SIZE, + .cia_max_keysize = DES_KEY_SIZE, + .cia_setkey = des_setkey, + .cia_encrypt = des_encrypt, + .cia_decrypt = des_decrypt, + } + } +}; + +static void ecb_des_ciper_loop(u8 *out, u8 *in, unsigned int n) +{ + while (likely(n)) { + des_hw_cipher(out, in); + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} + +static void ecb_des3_ede_encrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n) +{ + while (likely(n)) { + des3_hw_ede_encrypt(keys, out, in); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} + +static void ecb_des3_ede_decrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n) +{ + while (likely(n)) { + des3_hw_ede_decrypt(keys, out, in); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} + +#ifdef DES3_EEE +static void ecb_des3_eee_encrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n) +{ + while (likely(n)) { + des3_hw_eee_encrypt(keys, out, in); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} + +static void ecb_des3_eee_decrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n) +{ + while (likely(n)) { + des3_hw_eee_decrypt(keys, out, in); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} +#endif + +static inline void ecb_des_cipher_n(struct ubicom32_des_ctx *uctx, enum des_ops op, u8 *out, u8 *in, unsigned int n) +{ + switch (op) { + case DES_ENCRYPT: + case DES_DECRYPT: + /* set the right algo, direction and key once */ + hw_crypto_set_ctrl(SEC_ALG_DES | (op == DES_ENCRYPT ? SEC_DIR_ENCRYPT : 0)); + des_hw_set_key(uctx->key, uctx->key_len); + ecb_des_ciper_loop(out, in, n); + break; + + case DES3_EDE_ENCRYPT: + ecb_des3_ede_encrypt_loop(uctx->key, out, in, n); + break; + + case DES3_EDE_DECRYPT: + ecb_des3_ede_decrypt_loop(uctx->key, out, in, n); + break; + +#ifdef DES3_EEE + case DES3_EEE_ENCRYPT: + ecb_des3_eee_encrypt_loop(uctx->key, out, in, n); + break; + + case DES3_EEE_DECRYPT: + ecb_des3_eee_decrypt_loop(uctx->key, out, in, n); + break; +#endif + } +} + +static inline void des_xor_2w(u32 *data, u32 *iv) +{ + data[0] ^= iv[0]; + data[1] ^= iv[1]; +} + +static void cbc_des_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + while (likely(n)) { + des_xor_2w((u32 *)in, (u32 *)iv); + des_hw_cipher(out, in); + SEC_COPY_2W(iv, out); + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} + +static void cbc_des_decrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + u8 next_iv[DES_BLOCK_SIZE]; + while (likely(n)) { + SEC_COPY_2W(next_iv, in); + des_hw_cipher(out, in); + des_xor_2w((u32 *)out, (u32 *)iv); + SEC_COPY_2W(iv, next_iv); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} + +static void cbc_des3_ede_encrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + while (likely(n)) { + des_xor_2w((u32 *)in, (u32 *)iv); + des3_hw_ede_encrypt(keys, out, in); + SEC_COPY_2W(iv, out); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} + +static void cbc_des3_ede_decrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + u8 next_iv[DES_BLOCK_SIZE]; + while (likely(n)) { + SEC_COPY_2W(next_iv, in); + des3_hw_ede_decrypt(keys, out, in); + des_xor_2w((u32 *)out, (u32 *)iv); + SEC_COPY_2W(iv, next_iv); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} + +#ifdef DES3_EEE +static void cbc_des3_eee_encrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + while (likely(n)) { + des_xor_2w((u32 *)in, (u32 *)iv); + des3_hw_eee_encrypt(keys, out, in); + SEC_COPY_2W(iv, out); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} + +static void cbc_des3_eee_decrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + u8 next_iv[DES_BLOCK_SIZE]; + while (likely(n)) { + SEC_COPY_2W(next_iv, in); + des3_hw_eee_decrypt(keys, out, in); + des_xor_2w((u32 *)out, (u32 *)iv); + SEC_COPY_2W(iv, next_iv); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + n -= DES_BLOCK_SIZE; + } +} +#endif + +static inline void cbc_des_cipher_n(struct ubicom32_des_ctx *uctx, enum des_ops op, u8 *out, u8 *in, u8 *iv, unsigned int n) +{ + switch (op) { + case DES_ENCRYPT: + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); + des_hw_set_key(uctx->key, uctx->key_len); + cbc_des_encrypt_loop(out, in, iv, n); + break; + + case DES_DECRYPT: + /* set the right algo, direction and key once */ + hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); + des_hw_set_key(uctx->key, uctx->key_len); + cbc_des_decrypt_loop(out, in, iv, n); + break; + + case DES3_EDE_ENCRYPT: + cbc_des3_ede_encrypt_loop(uctx->key, out, in, iv, n); + break; + + case DES3_EDE_DECRYPT: + cbc_des3_ede_decrypt_loop(uctx->key, out, in, iv, n); + break; + +#ifdef DES3_EEE + case DES3_EEE_ENCRYPT: + cbc_des3_eee_encrypt_loop(uctx->key, out, in, iv, n); + break; + + case DES3_EEE_DECRYPT: + cbc_des3_eee_decrypt_loop(uctx->key, out, in, iv, n); + break; +#endif + } +} + +static int des_cipher(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes, u32 extra_flags, enum des_ops op) +{ + struct ubicom32_des_ctx *uctx = crypto_blkcipher_ctx(desc->tfm); + int ret; + + struct blkcipher_walk walk; + blkcipher_walk_init(&walk, dst, src, nbytes); + ret = blkcipher_walk_virt(desc, &walk); + if (ret) { + return ret; + } + + hw_crypto_lock(); + hw_crypto_check(); + + while ((nbytes = walk.nbytes)) { + /* only use complete blocks */ + unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1); + u8 *out = walk.dst.virt.addr; + u8 *in = walk.src.virt.addr; + + /* finish n/16 blocks */ + if (extra_flags & SEC_CBC_SET) { + cbc_des_cipher_n(uctx, op, out, in, walk.iv, n); + } else { + ecb_des_cipher_n(uctx, op, out, in, n); + } + + nbytes &= DES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, &walk, nbytes); + } + + hw_crypto_unlock(); + return ret; +} + +static int ecb_des_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES_ENCRYPT); +} + +static int ecb_des_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES_DECRYPT); +} + +static struct crypto_alg ecb_des_alg = { + .cra_name = "ecb(des)", + .cra_driver_name = "ecb-des-ubicom32", + .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_des_ctx), + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .setkey = des_setkey, + .encrypt = ecb_des_encrypt, + .decrypt = ecb_des_decrypt, + } + } +}; + +static int cbc_des_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES_ENCRYPT); +} + +static int cbc_des_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES_DECRYPT); +} + +static struct crypto_alg cbc_des_alg = { + .cra_name = "cbc(des)", + .cra_driver_name = "cbc-des-ubicom32", + .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_des_ctx), + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = des_setkey, + .encrypt = cbc_des_encrypt, + .decrypt = cbc_des_decrypt, + } + } +}; + +/* + * RFC2451: + * + * For DES-EDE3, there is no known need to reject weak or + * complementation keys. Any weakness is obviated by the use of + * multiple keys. + * + * However, if the first two or last two independent 64-bit keys are + * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the + * same as DES. Implementers MUST reject keys that exhibit this + * property. + * + */ +static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + int i, ret; + struct ubicom32_des_ctx *dctx = crypto_tfm_ctx(tfm); + const u8 *temp_key = key; + u32 *flags = &tfm->crt_flags; + + if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && + memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2], + DES_KEY_SIZE))) { + + *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; + return -EINVAL; + } + for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) { + ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags); + if (ret < 0) + return ret; + } + memcpy(dctx->key, key, keylen); + dctx->ctrl = SEC_ALG_DES; //hw 3DES not working yet + dctx->key_len = keylen; + return 0; +} + +static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm); + + hw_crypto_lock(); + hw_crypto_check(); + + des3_hw_ede_encrypt(uctx->key, dst, src); + + hw_crypto_unlock(); +} + +static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm); + + hw_crypto_lock(); + hw_crypto_check(); + + des3_hw_ede_decrypt(uctx->key, dst, src); + + hw_crypto_unlock(); +} + +static struct crypto_alg des3_192_alg = { + .cra_name = "des3_ede", + .cra_driver_name = "des3_ede-ubicom32", + .cra_priority = CRYPTO_UBICOM32_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES3_192_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_des_ctx), + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = DES3_192_KEY_SIZE, + .cia_max_keysize = DES3_192_KEY_SIZE, + .cia_setkey = des3_192_setkey, + .cia_encrypt = des3_192_encrypt, + .cia_decrypt = des3_192_decrypt, + } + } +}; + +static int ecb_des3_192_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES3_EDE_ENCRYPT); +} + +static int ecb_des3_192_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES3_EDE_DECRYPT); +} + +static struct crypto_alg ecb_des3_192_alg = { + .cra_name = "ecb(des3_ede)", + .cra_driver_name = "ecb-des3_ede-ubicom32", + .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES3_192_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_des_ctx), + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT( + ecb_des3_192_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES3_192_KEY_SIZE, + .max_keysize = DES3_192_KEY_SIZE, + .setkey = des3_192_setkey, + .encrypt = ecb_des3_192_encrypt, + .decrypt = ecb_des3_192_decrypt, + } + } +}; + +static int cbc_des3_192_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES3_EDE_ENCRYPT); +} + +static int cbc_des3_192_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES3_EDE_DECRYPT); +} + +static struct crypto_alg cbc_des3_192_alg = { + .cra_name = "cbc(des3_ede)", + .cra_driver_name = "cbc-des3_ede-ubicom32", + .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES3_192_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_des_ctx), + .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT( + cbc_des3_192_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES3_192_KEY_SIZE, + .max_keysize = DES3_192_KEY_SIZE, + .ivsize = DES3_192_BLOCK_SIZE, + .setkey = des3_192_setkey, + .encrypt = cbc_des3_192_encrypt, + .decrypt = cbc_des3_192_decrypt, + } + } +}; + +static int init(void) +{ + int ret = 0; + + hw_crypto_init(); + + ret = crypto_register_alg(&des_alg); + if (ret) + goto des_err; + ret = crypto_register_alg(&ecb_des_alg); + if (ret) + goto ecb_des_err; + ret = crypto_register_alg(&cbc_des_alg); + if (ret) + goto cbc_des_err; + + ret = crypto_register_alg(&des3_192_alg); + if (ret) + goto des3_192_err; + ret = crypto_register_alg(&ecb_des3_192_alg); + if (ret) + goto ecb_des3_192_err; + ret = crypto_register_alg(&cbc_des3_192_alg); + if (ret) + goto cbc_des3_192_err; + +out: + return ret; + +cbc_des3_192_err: + crypto_unregister_alg(&ecb_des3_192_alg); +ecb_des3_192_err: + crypto_unregister_alg(&des3_192_alg); +des3_192_err: + crypto_unregister_alg(&cbc_des_alg); +cbc_des_err: + crypto_unregister_alg(&ecb_des_alg); +ecb_des_err: + crypto_unregister_alg(&des_alg); +des_err: + goto out; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&cbc_des3_192_alg); + crypto_unregister_alg(&ecb_des3_192_alg); + crypto_unregister_alg(&des3_192_alg); + crypto_unregister_alg(&cbc_des_alg); + crypto_unregister_alg(&ecb_des_alg); + crypto_unregister_alg(&des_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_ALIAS("des"); +MODULE_ALIAS("des3_ede"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32.c new file mode 100644 index 000000000..1f2b978ea --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32.c @@ -0,0 +1,200 @@ +/* + * arch/ubicom32/crypto/md5_ubicom32.c + * Ubicom32 implementation of the MD5 Secure Hash Algorithm + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include + +#include "crypto_ubicom32.h" + +#define MD5_DIGEST_SIZE 16 +#define MD5_BLOCK_SIZE 64 +#define MD5_HASH_WORDS 4 + +extern void _md5_ip5k_init_digest(u32_t *digest); +extern void _md5_ip5k_transform(u32_t *data_input); +extern void _md5_ip5k_get_digest(u32_t *digest); + +struct ubicom32_md5_ctx { + u64 count; /* message length */ + u32 state[MD5_HASH_WORDS]; + u8 buf[2 * MD5_BLOCK_SIZE]; +}; + +static void md5_init(struct crypto_tfm *tfm) +{ + struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm); + mctx->state[0] = 0x01234567; + mctx->state[1] = 0x89abcdef; + mctx->state[2] = 0xfedcba98; + mctx->state[3] = 0x76543210; + + mctx->count = 0; +} + +static inline void _md5_process(u32 *digest, const u8 *data) +{ + _md5_ip5k_transform((u32 *)data); +} + +static void md5_update(struct crypto_tfm *tfm, const u8 *data, + unsigned int len) +{ + struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm); + int index, clen; + + /* how much is already in the buffer? */ + index = mctx->count & 0x3f; + + mctx->count += len; + + if (index + len < MD5_BLOCK_SIZE) { + goto store_only; + } + + hw_crypto_lock(); + hw_crypto_check(); + + /* init digest set ctrl register too */ + _md5_ip5k_init_digest(mctx->state); + + if (unlikely(index == 0 && SEC_ALIGNED(data))) { +fast_process: + while (len >= MD5_BLOCK_SIZE) { + _md5_process(mctx->state, data); + data += MD5_BLOCK_SIZE; + len -= MD5_BLOCK_SIZE; + } + goto store; + } + + /* process one stored block */ + if (index) { + clen = MD5_BLOCK_SIZE - index; + memcpy(mctx->buf + index, data, clen); + _md5_process(mctx->state, mctx->buf); + data += clen; + len -= clen; + index = 0; + } + + if (likely(SEC_ALIGNED(data))) { + goto fast_process; + } + + /* process as many blocks as possible */ + while (len >= MD5_BLOCK_SIZE) { + memcpy(mctx->buf, data, MD5_BLOCK_SIZE); + _md5_process(mctx->state, mctx->buf); + data += MD5_BLOCK_SIZE; + len -= MD5_BLOCK_SIZE; + } + +store: + _md5_ip5k_get_digest(mctx->state); + hw_crypto_unlock(); + +store_only: + /* anything left? */ + if (len) + memcpy(mctx->buf + index , data, len); +} + +/* Add padding and return the message digest. */ +static void md5_final(struct crypto_tfm *tfm, u8 *out) +{ + struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm); + u32 bits[2]; + unsigned int index, end; + + /* must perform manual padding */ + index = mctx->count & 0x3f; + end = (index < 56) ? MD5_BLOCK_SIZE : (2 * MD5_BLOCK_SIZE); + + /* start pad with 1 */ + mctx->buf[index] = 0x80; + + /* pad with zeros */ + index++; + memset(mctx->buf + index, 0x00, end - index - 8); + + /* append message length */ + bits[0] = mctx->count << 3; + bits[1] = mctx->count >> 29; + __cpu_to_le32s(bits); + __cpu_to_le32s(bits + 1); + + memcpy(mctx->buf + end - 8, &bits, sizeof(bits)); + + /* force to use the mctx->buf and ignore the partial buf */ + mctx->count = mctx->count & ~0x3f; + md5_update(tfm, mctx->buf, end); + + /* copy digest to out */ + memcpy(out, mctx->state, MD5_DIGEST_SIZE); + + /* wipe context */ + memset(mctx, 0, sizeof *mctx); +} + +static struct crypto_alg alg = { + .cra_name = "md5", + .cra_driver_name= "md5-ubicom32", + .cra_priority = CRYPTO_UBICOM32_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = MD5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_md5_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { + .digest = { + .dia_digestsize = MD5_DIGEST_SIZE, + .dia_init = md5_init, + .dia_update = md5_update, + .dia_final = md5_final, + } + } +}; + +static int __init init(void) +{ + hw_crypto_init(); + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_ALIAS("md5"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MD5 Secure Hash Algorithm"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32_asm.S b/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32_asm.S new file mode 100644 index 000000000..963a3579a --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32_asm.S @@ -0,0 +1,234 @@ +/* + * arch/ubicom32/crypto/md5_ubicom32_asm.S + * MD5 (Message Digest 5) support for Ubicom32 v3 architecture + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#define __ASM__ +#include + +#ifndef RP +#define RP A5 +#endif + +;***************************************************************************************** +; The function prototypes +;***************************************************************************************** +; void md5_ip5k_init(void) +; void md5_ip5k_transform(u32_t *data_input) +; void md5_get_digest(u32_t *digest) + +;***************************************************************************************** +; Inputs +;*****************************************************************************************; +; data_input is the pointer to the block of data over which the digest will be calculated. +; It should be word aligned. +; +; digest is the pointer to the block of data into which the digest (the output) will be written. +; It should be word aligned. +; + +;***************************************************************************************** +; Outputs +;***************************************************************************************** +; None + +;***************************************************************************************** +; An: Address Registers +;***************************************************************************************** +#define an_digest A3 +#define an_data_input A3 +#define an_security_block A4 + +;***************************************************************************************** +; Hash Constants +;***************************************************************************************** +#define HASH_MD5_IN0 0x01234567 +#define HASH_MD5_IN1 0x89abcdef +#define HASH_MD5_IN2 0xfedcba98 +#define HASH_MD5_IN3 0x76543210 + +#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2 +#define HASH_SECURITY_BLOCK_CONTROL_INIT_MD5 ((1 << 4) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION) + +;***************************************************************************************** +; Hash related defines +;***************************************************************************************** +#define hash_control 0x00(an_security_block) +#define hash_control_low 0x02(an_security_block) +#define hash_status 0x04(an_security_block) + +#define hash_input_0 0x30(an_security_block) +#define hash_input_1 0x34(an_security_block) +#define hash_input_2 0x38(an_security_block) +#define hash_input_3 0x3c(an_security_block) +#define hash_input_4 0x40(an_security_block) + +#define hash_output_0 0x70(an_security_block) +#define hash_output_0_low 0x72(an_security_block) +#define hash_output_1 0x74(an_security_block) +#define hash_output_1_low 0x76(an_security_block) +#define hash_output_2 0x78(an_security_block) +#define hash_output_2_low 0x7a(an_security_block) +#define hash_output_3 0x7c(an_security_block) +#define hash_output_3_low 0x7e(an_security_block) + +;***************************************************************************************** +; Assembly macros +;***************************************************************************************** + ; C compiler reserves RP (A5) for return address during subroutine call. + ; Use RP to return to caller +.macro call_return_macro + calli RP, 0(RP) +.endm + +#if 0 +;***************************************************************************************** +; void md5_ip5k_init(void) +; initialize the output registers of the hash module +; + ;.section .text.md5_ip5k_init,"ax",@progbits + .section .text + .global _md5_ip5k_init + .func md5_ip5k_init, _md5_ip5k_init + +_md5_ip5k_init: + moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS + + movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5) + movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5) + + movei hash_output_0, #%hi(HASH_MD5_IN0) + movei hash_output_0_low, #%lo(HASH_MD5_IN0) + + movei hash_output_1, #%hi(HASH_MD5_IN1) + movei hash_output_1_low, #%lo(HASH_MD5_IN1) + + movei hash_output_2, #%hi(HASH_MD5_IN2) + movei hash_output_2_low, #%lo(HASH_MD5_IN2) + + movei hash_output_3, #%hi(HASH_MD5_IN3) + movei hash_output_3_low, #%lo(HASH_MD5_IN3) + + call_return_macro + .endfunc +#endif + +;***************************************************************************************** +; void md5_ip5k_init_digest(u32_t *hash_input) +; initialize the output registers of the hash module + + ;.section .text.md5_ip5k_init_digest,"ax",@progbits + .section .text + .global _md5_ip5k_init_digest + .func md5_ip5k_init_digest, _md5_ip5k_init_digest + +_md5_ip5k_init_digest: + movea an_data_input, D0 + + moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS + + movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5) + movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5) + + move.4 hash_output_0, (an_data_input)4++ + move.4 hash_output_1, (an_data_input)4++ + move.4 hash_output_2, (an_data_input)4++ + move.4 hash_output_3, (an_data_input)4++ + + call_return_macro + .endfunc + +;***************************************************************************************** +; void md5_ip5k_transform(u32_t *data_input) +; performs intermediate transformation step for the hash calculation +; + ;.sect .text.md5_ip5k_transform,"ax",@progbits + .section .text + .global _md5_ip5k_transform + .func md5_ip5k_transform, _md5_ip5k_transform + +_md5_ip5k_transform: + movea an_data_input, D0 + + moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS + + ; Write the first 128bits (16 bytes) + move.4 hash_input_0, (an_data_input)4++ + move.4 hash_input_1, (an_data_input)4++ + move.4 hash_input_2, (an_data_input)4++ + move.4 hash_input_3, (an_data_input)4++ + move.4 hash_input_4, D0 + + move.4 hash_input_0, (an_data_input)4++ + move.4 hash_input_1, (an_data_input)4++ + move.4 hash_input_2, (an_data_input)4++ + move.4 hash_input_3, (an_data_input)4++ + move.4 hash_input_4, D0 + + move.4 hash_input_0, (an_data_input)4++ + move.4 hash_input_1, (an_data_input)4++ + move.4 hash_input_2, (an_data_input)4++ + move.4 hash_input_3, (an_data_input)4++ + move.4 hash_input_4, D0 + + move.4 hash_input_0, (an_data_input)4++ + move.4 hash_input_1, (an_data_input)4++ + move.4 hash_input_2, (an_data_input)4++ + move.4 hash_input_3, (an_data_input)4++ + move.4 hash_input_4, D0 + + pipe_flush 0 + +md5_ip5k_transform_wait: + ; wait for the module to calculate the output hash + btst hash_status, #0 + jmpne.f md5_ip5k_transform_wait + + call_return_macro + .endfunc + +;***************************************************************************************** +; void md5_ip5k_get_digest(u32_t *digest) +; Return the hash of the input data +; + ;.sect .text.md5_get_digest,"ax",@progbits + .section .text + .global _md5_ip5k_get_digest + .func md5_ip5k_get_digest, _md5_ip5k_get_digest + +_md5_ip5k_get_digest: + movea an_digest, D0 + + moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS + + ; we have finished + move.4 0(an_digest), hash_output_0 + move.4 4(an_digest), hash_output_1 + move.4 8(an_digest), hash_output_2 + move.4 12(an_digest), hash_output_3 + + call_return_macro + .endfunc diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32.c new file mode 100644 index 000000000..2d0c870eb --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32.c @@ -0,0 +1,354 @@ +/* + * arch/ubicom32/crypto/sha1_ubicom32.c + * Ubicom32 implementation of the SHA1 Secure Hash Algorithm. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include + +#include "crypto_ubicom32.h" +#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2 +#define HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1 ((1 << 5) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION) + +struct ubicom32_sha1_ctx { + u64 count; /* message length */ + u32 state[5]; + u8 buf[2 * SHA1_BLOCK_SIZE]; +}; + +static inline void sha1_clear_2ws(u8 *buf, int wc) +{ + asm volatile ( + "1: move.4 (%0)4++, #0 \n\t" + " move.4 (%0)4++, #0 \n\t" + " sub.4 %1, #2, %1 \n\t" + " jmple.f 1b \n\t" + : + : "a" (buf), "d" (wc) + : "cc" + ); +} + +/* only wipe out count, state, and 1st half of buf - 9 bytes at most */ +#define sha1_wipe_out(sctx) sha1_clear_2ws((u8 *)sctx, 2 + 5 + 16 - 2) + +static inline void sha1_init_digest(u32 *digest) +{ + hw_crypto_set_ctrl(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1); + asm volatile ( + " ; move digests to hash_output regs \n\t" + " move.4 0x70(%0), 0x0(%1) \n\t" + " move.4 0x74(%0), 0x4(%1) \n\t" + " move.4 0x78(%0), 0x8(%1) \n\t" + " move.4 0x7c(%0), 0xc(%1) \n\t" + " move.4 0x80(%0), 0x10(%1) \n\t" + : + : "a" (SEC_BASE), "a" (digest) + ); +} + +static inline void sha1_transform_feed(const u8 *in) +{ + asm volatile ( + " ; write the 1st 16 bytes \n\t" + " move.4 0x30(%0), 0x0(%1) \n\t" + " move.4 0x34(%0), 0x4(%1) \n\t" + " move.4 0x38(%0), 0x8(%1) \n\t" + " move.4 0x3c(%0), 0xc(%1) \n\t" + " move.4 0x40(%0), %1 \n\t" + " ; write the 2nd 16 bytes \n\t" + " move.4 0x30(%0), 0x10(%1) \n\t" + " move.4 0x34(%0), 0x14(%1) \n\t" + " move.4 0x38(%0), 0x18(%1) \n\t" + " move.4 0x3c(%0), 0x1c(%1) \n\t" + " move.4 0x40(%0), %1 \n\t" + " ; write the 3rd 16 bytes \n\t" + " move.4 0x30(%0), 0x20(%1) \n\t" + " move.4 0x34(%0), 0x24(%1) \n\t" + " move.4 0x38(%0), 0x28(%1) \n\t" + " move.4 0x3c(%0), 0x2c(%1) \n\t" + " move.4 0x40(%0), %1 \n\t" + " ; write the 4th 16 bytes \n\t" + " move.4 0x30(%0), 0x30(%1) \n\t" + " move.4 0x34(%0), 0x34(%1) \n\t" + " move.4 0x38(%0), 0x38(%1) \n\t" + " move.4 0x3c(%0), 0x3c(%1) \n\t" + " move.4 0x40(%0), %1 \n\t" + " pipe_flush 0 \n\t" + : + : "a"(SEC_BASE), "a"(in) + ); +} + +static inline void sha1_transform_wait(void) +{ + asm volatile ( + " btst 0x04(%0), #0 \n\t" + " jmpne.f -4 \n\t" + : + : "a"(SEC_BASE) + : "cc" + ); +} + +static inline void sha1_output_digest(u32 *digest) +{ + asm volatile ( + " move.4 0x0(%1), 0x70(%0) \n\t" + " move.4 0x4(%1), 0x74(%0) \n\t" + " move.4 0x8(%1), 0x78(%0) \n\t" + " move.4 0xc(%1), 0x7c(%0) \n\t" + " move.4 0x10(%1), 0x80(%0) \n\t" + : + : "a" (SEC_BASE), "a" (digest) + ); +} + +static __ocm_text void sha1_init(struct crypto_tfm *tfm) +{ + struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm); + + sctx->state[0] = SHA1_H0; + sctx->state[1] = SHA1_H1; + sctx->state[2] = SHA1_H2; + sctx->state[3] = SHA1_H3; + sctx->state[4] = SHA1_H4; + sctx->count = 0; +} + +static void __ocm_text sha1_update(struct crypto_tfm *tfm, const u8 *data, + unsigned int len) +{ + struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm); + int index, clen; + + /* how much is already in the buffer? */ + index = sctx->count & 0x3f; + + sctx->count += len; + + if (index + len < SHA1_BLOCK_SIZE) { + goto store_only; + } + + hw_crypto_lock(); + hw_crypto_check(); + + /* init digest set ctrl register too */ + sha1_init_digest(sctx->state); + + if (unlikely(index == 0 && SEC_ALIGNED(data))) { +fast_process: +#if CRYPTO_UBICOM32_LOOP_ASM + if (likely(len >= SHA1_BLOCK_SIZE)) { + register unsigned int cnt = len >> 6; // loop = len / 64; + sha1_transform_feed(data); + data += SHA1_BLOCK_SIZE; + + /* cnt is pre-decremented in the loop */ + asm volatile ( + "; while (--loop): work on 2nd block \n\t" + "1: add.4 %2, #-1, %2 \n\t" + " jmpeq.f 5f \n\t" + " \n\t" + " ; write the 1st 16 bytes \n\t" + " move.4 0x30(%1), (%0)4++ \n\t" + " move.4 0x34(%1), (%0)4++ \n\t" + " move.4 0x38(%1), (%0)4++ \n\t" + " move.4 0x3c(%1), (%0)4++ \n\t" + " ; can not kick off hw before it \n\t" + " ; is done with the prev block \n\t" + " \n\t" + " btst 0x04(%1), #0 \n\t" + " jmpne.f -4 \n\t" + " \n\t" + " ; tell hw to load 1st 16 bytes \n\t" + " move.4 0x40(%1), %2 \n\t" + " \n\t" + " ; write the 2nd 16 bytes \n\t" + " move.4 0x30(%1), (%0)4++ \n\t" + " move.4 0x34(%1), (%0)4++ \n\t" + " move.4 0x38(%1), (%0)4++ \n\t" + " move.4 0x3c(%1), (%0)4++ \n\t" + " move.4 0x40(%1), %2 \n\t" + " \n\t" + " ; write the 3rd 16 bytes \n\t" + " move.4 0x30(%1), (%0)4++ \n\t" + " move.4 0x34(%1), (%0)4++ \n\t" + " move.4 0x38(%1), (%0)4++ \n\t" + " move.4 0x3c(%1), (%0)4++ \n\t" + " move.4 0x40(%1), %2 \n\t" + " \n\t" + " ; write the 4th 16 bytes \n\t" + " move.4 0x30(%1), (%0)4++ \n\t" + " move.4 0x34(%1), (%0)4++ \n\t" + " move.4 0x38(%1), (%0)4++ \n\t" + " move.4 0x3c(%1), (%0)4++ \n\t" + " move.4 0x40(%1), %2 \n\t" + " \n\t" + "; no need flush, enough insts \n\t" + "; before next hw wait \n\t" + " \n\t" + "; go back to loop \n\t" + " jmpt 1b \n\t" + " \n\t" + "; wait hw for last block \n\t" + "5: btst 0x04(%1), #0 \n\t" + " jmpne.f -4 \n\t" + " \n\t" + : "+a" (data) + : "a"( SEC_BASE), "d" (cnt) + : "cc" + ); + + len = len & (64 - 1); + } +#else + while (likely(len >= SHA1_BLOCK_SIZE)) { + sha1_transform_feed(data); + data += SHA1_BLOCK_SIZE; + len -= SHA1_BLOCK_SIZE; + sha1_transform_wait(); + } +#endif + goto store; + } + + /* process one stored block */ + if (index) { + clen = SHA1_BLOCK_SIZE - index; + memcpy(sctx->buf + index, data, clen); + sha1_transform_feed(sctx->buf); + data += clen; + len -= clen; + index = 0; + sha1_transform_wait(); + } + + if (likely(SEC_ALIGNED(data))) { + goto fast_process; + } + + /* process as many blocks as possible */ + if (likely(len >= SHA1_BLOCK_SIZE)) { + memcpy(sctx->buf, data, SHA1_BLOCK_SIZE); + do { + sha1_transform_feed(sctx->buf); + data += SHA1_BLOCK_SIZE; + len -= SHA1_BLOCK_SIZE; + if (likely(len >= SHA1_BLOCK_SIZE)) { + memcpy(sctx->buf, data, SHA1_BLOCK_SIZE); + sha1_transform_wait(); + continue; + } + /* it is the last block */ + sha1_transform_wait(); + break; + } while (1); + } + +store: + sha1_output_digest(sctx->state); + hw_crypto_unlock(); + +store_only: + /* anything left? */ + if (len) + memcpy(sctx->buf + index , data, len); +} + +/* Add padding and return the message digest. */ +static void __ocm_text sha1_final(struct crypto_tfm *tfm, u8 *out) +{ + struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm); + u64 bits; + unsigned int index, end; + + /* must perform manual padding */ + index = sctx->count & 0x3f; + end = (index < 56) ? SHA1_BLOCK_SIZE : (2 * SHA1_BLOCK_SIZE); + + /* start pad with 1 */ + sctx->buf[index] = 0x80; + + /* pad with zeros */ + index++; + memset(sctx->buf + index, 0x00, end - index - 8); + + /* append message length */ + bits = sctx->count << 3 ; + SEC_COPY_2W(sctx->buf + end - 8, &bits); + + /* force to use the sctx->buf and ignore the partial buf */ + sctx->count = sctx->count & ~0x3f; + sha1_update(tfm, sctx->buf, end); + + /* copy digest to out */ + SEC_COPY_5W(out, sctx->state); + + /* wipe context */ + sha1_wipe_out(sctx); +} + +static struct crypto_alg alg = { + .cra_name = "sha1", + .cra_driver_name= "sha1-ubicom32", + .cra_priority = CRYPTO_UBICOM32_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ubicom32_sha1_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { + .digest = { + .dia_digestsize = SHA1_DIGEST_SIZE, + .dia_init = sha1_init, + .dia_update = sha1_update, + .dia_final = sha1_final, + } + } +}; + +static int __init init(void) +{ + hw_crypto_init(); + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_ALIAS("sha1"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32_asm.S b/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32_asm.S new file mode 100644 index 000000000..f610b7e9f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32_asm.S @@ -0,0 +1,244 @@ +/* + * arch/ubicom32/crypto/sha1_ubicom32_asm.S + * SHA1 hash support for Ubicom32 architecture V3. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#define __ASM__ +#include + +#ifndef RP +#define RP A5 +#endif + +;***************************************************************************************** +; The function prototype +;***************************************************************************************** +; void sha1_ip5k_init(void) +; void sha1_ip5k_transform(u32_t *data_input) +; void sha1_ip5k_output(u32_t *digest) + +;***************************************************************************************** +; Inputs +;***************************************************************************************** +; data_input is the pointer to the block of data over which the digest will be calculated. +; It should be word aligned. +; +; digest is the pointer to the block of data into which the digest (the output) will be written. +; It should be word aligned. +; + +;***************************************************************************************** +; Outputs +;***************************************************************************************** +; None + +;***************************************************************************************** +; Hash Constants +;***************************************************************************************** +#define HASH_SHA1_IN0 0x67452301 +#define HASH_SHA1_IN1 0xefcdab89 +#define HASH_SHA1_IN2 0x98badcfe +#define HASH_SHA1_IN3 0x10325476 +#define HASH_SHA1_IN4 0xc3d2e1f0 + +#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2 +#define HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1 ((1 << 5) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION) + +;***************************************************************************************** +; An: Address Registers +;***************************************************************************************** +#define an_digest a4 +#define an_data_input a4 +#define an_security_block a3 + +;***************************************************************************************** +; Hash related defines +;***************************************************************************************** +#define hash_control 0x00(an_security_block) +#define hash_control_low 0x02(an_security_block) +#define hash_status 0x04(an_security_block) + +#define hash_input_0 0x30(an_security_block) +#define hash_input_1 0x34(an_security_block) +#define hash_input_2 0x38(an_security_block) +#define hash_input_3 0x3c(an_security_block) +#define hash_input_4 0x40(an_security_block) + +#define hash_output_0 0x70(an_security_block) +#define hash_output_0_low 0x72(an_security_block) +#define hash_output_1 0x74(an_security_block) +#define hash_output_1_low 0x76(an_security_block) +#define hash_output_2 0x78(an_security_block) +#define hash_output_2_low 0x7a(an_security_block) +#define hash_output_3 0x7c(an_security_block) +#define hash_output_3_low 0x7e(an_security_block) +#define hash_output_4 0x80(an_security_block) +#define hash_output_4_low 0x82(an_security_block) + +;***************************************************************************************** +; Assembly macros +;***************************************************************************************** + ; C compiler reserves RP (A5) for return address during subroutine call. + ; Use RP to return to caller +.macro call_return_macro + calli RP, 0(RP) +.endm + +;***************************************************************************************** +; void sha1_ip5k_init(void) +; initialize the output registers of the hash module + + ;.section .text.sha1_ip5k_init,"ax",@progbits + .section .ocm_text,"ax",@progbits + .global _sha1_ip5k_init + .func sha1_ip5k_init, _sha1_ip5k_init + +_sha1_ip5k_init: + moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS + + movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1) + movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1) + + movei hash_output_0, #%hi(HASH_SHA1_IN0) + movei hash_output_0_low, #%lo(HASH_SHA1_IN0) + + movei hash_output_1, #%hi(HASH_SHA1_IN1) + movei hash_output_1_low, #%lo(HASH_SHA1_IN1) + + movei hash_output_2, #%hi(HASH_SHA1_IN2) + movei hash_output_2_low, #%lo(HASH_SHA1_IN2) + + movei hash_output_3, #%hi(HASH_SHA1_IN3) + movei hash_output_3_low, #%lo(HASH_SHA1_IN3) + + movei hash_output_4, #%hi(HASH_SHA1_IN4) + movei hash_output_4_low, #%lo(HASH_SHA1_IN4) + + call_return_macro + .endfunc + +;***************************************************************************************** +; void sha1_ip5k_init_digest(u32_t *hash_input) +; initialize the output registers of the hash module + + ;.section .text.sha1_ip5k_init_digest,"ax",@progbits + .section .ocm_text,"ax",@progbits + .global _sha1_ip5k_init_digest + .func sha1_ip5k_init_digest, _sha1_ip5k_init_digest + +_sha1_ip5k_init_digest: + movea an_data_input, D0 + + moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS + + movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1) + movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1) + + move.4 hash_output_0, (an_data_input)4++ + move.4 hash_output_1, (an_data_input)4++ + move.4 hash_output_2, (an_data_input)4++ + move.4 hash_output_3, (an_data_input)4++ + move.4 hash_output_4, (an_data_input)4++ + + call_return_macro + .endfunc + +;***************************************************************************************** +; void sha1_ip5k_transform(u32_t *data_input) +; performs intermediate transformation step for the hash calculation + + ;.section .text.sha1_ip5k_transform,"ax",@progbits + .section .ocm_text,"ax",@progbits + .global _sha1_ip5k_transform + .func sha1_ip5k_transform, _sha1_ip5k_transform + +_sha1_ip5k_transform: + movea an_data_input, D0 + + moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS + + ; Write the first 128bits (16 bytes) + move.4 hash_input_0, (an_data_input)4++ + move.4 hash_input_1, (an_data_input)4++ + move.4 hash_input_2, (an_data_input)4++ + move.4 hash_input_3, (an_data_input)4++ + move.4 hash_input_4, D0 + + move.4 hash_input_0, (an_data_input)4++ + move.4 hash_input_1, (an_data_input)4++ + move.4 hash_input_2, (an_data_input)4++ + move.4 hash_input_3, (an_data_input)4++ + move.4 hash_input_4, D0 + + move.4 hash_input_0, (an_data_input)4++ + move.4 hash_input_1, (an_data_input)4++ + move.4 hash_input_2, (an_data_input)4++ + move.4 hash_input_3, (an_data_input)4++ + move.4 hash_input_4, D0 + + move.4 hash_input_0, (an_data_input)4++ + move.4 hash_input_1, (an_data_input)4++ + move.4 hash_input_2, (an_data_input)4++ + move.4 hash_input_3, (an_data_input)4++ + move.4 hash_input_4, D0 + + pipe_flush 0 + +sha1_ip5k_transform_wait: + ; wait for the module to calculate the output hash + btst hash_status, #0 + jmpne.f sha1_ip5k_transform_wait + + call_return_macro + .endfunc + +;***************************************************************************************** +; void sha1_ip5k_output(u32_t *digest) +; Return the hash of the input data + + ;.section .text.sha1_ip5k_output,"ax",@progbits + .section .ocm_text,"ax",@progbits + .global _sha1_ip5k_output + .func sha1_ip5k_output, _sha1_ip5k_output + +_sha1_ip5k_output: + movea an_digest, D0 + + moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS + + ; we have finished + move.4 0(an_digest), hash_output_0 + move.4 4(an_digest), hash_output_1 + move.4 8(an_digest), hash_output_2 + move.4 12(an_digest), hash_output_3 + move.4 16(an_digest), hash_output_4 + + call_return_macro + .endfunc + +;***************************************************************************************** +;END ;End of program code +;***************************************************************************************** diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/.gitignore b/target/linux/ubicom32/files/arch/ubicom32/include/asm/.gitignore new file mode 100644 index 000000000..c6b1010db --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/.gitignore @@ -0,0 +1 @@ +/ocm_size.h diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/Kbuild b/target/linux/ubicom32/files/arch/ubicom32/include/asm/Kbuild new file mode 100644 index 000000000..c68e1680d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/Kbuild @@ -0,0 +1 @@ +include include/asm-generic/Kbuild.asm diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/a.out.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/a.out.h new file mode 100644 index 000000000..8eb0ade88 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/a.out.h @@ -0,0 +1,47 @@ +/* + * arch/ubicom32/include/asm/a.out.h + * Definitions for Ubicom32 a.out executable format. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_A_OUT_H +#define _ASM_UBICOM32_A_OUT_H + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#define N_TRSIZE(a) ((a).a_trsize) +#define N_DRSIZE(a) ((a).a_drsize) +#define N_SYMSIZE(a) ((a).a_syms) + +#endif /* _ASM_UBICOM32_A_OUT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h new file mode 100644 index 000000000..aaf772602 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h @@ -0,0 +1,353 @@ +/* + * arch/ubicom32/include/asm/atomic.h + * Atomic operations definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_ATOMIC_H +#define _ASM_UBICOM32_ATOMIC_H + +#include +#include +#include + +/* + * Most instructions on the Ubicom32 processor are atomic in that they + * execute in one clock cycle. However, Linux has several operations + * (e.g. compare and swap) which will require more than a single instruction + * to perform. To achieve this, the Ubicom32 processor uses a single + * global bit in a scratchpad register as a critical section lock. All + * atomic operations acquire this lock. + * + * NOTE: To AVOID DEADLOCK(s), the atomic lock must only be used for atomic + * operations or by the ldsr to avoid disabling a thread performing an atomic + * operation. + * + * Do not attempt to disable interrupts while holding the atomic operations + * lock or you will DEADLOCK the system. + */ + +#define ATOMIC_INIT(i) { (i) } + +/* + * __atomic_add() + * Add i to v and return the result. + */ +static inline void __atomic_add(int i, atomic_t *v) +{ + atomic_t *vt = v; + + __atomic_lock_acquire(); + vt->counter += i; + __atomic_lock_release(); +} + +/* + * __atomic_sub() + * Subtract i from v and return the result. + */ +static inline void __atomic_sub(int i, atomic_t *v) +{ + atomic_t *vt = v; + + __atomic_lock_acquire(); + vt->counter -= i; + __atomic_lock_release(); +} + +/* + * __atomic_add_return() + * Add i to v and return the result. + * + * The implementation here looks rather odd because we appear to be doing + * the addition twice. In fact that's exactly what we're doing but with + * the ubicom32 instruction set we can do the inner load and add with two + * instructions whereas generating both the atomic result and the "ret" + * result requires three instructions. The second add is generally only as + * costly as a move instruction and in cases where we compare the result + * with a constant the compiler can fold two constant values and do a + * single instruction, thus saving an instruction overall! + * + * At the worst we save one instruction inside the atomic lock. + */ +static inline int __atomic_add_return(int i, atomic_t *v) +{ + int ret; + atomic_t *vt = v; + + __atomic_lock_acquire(); + ret = vt->counter; + vt->counter = ret + i; + __atomic_lock_release(); + + return ret + i; +} + +/* + * __atomic_sub_return() + * Subtract i from v and return the result. + * + * The implementation here looks rather odd because we appear to be doing + * the subtraction twice. In fact that's exactly what we're doing but with + * the ubicom32 instruction set we can do the inner load and sub with two + * instructions whereas generating both the atomic result and the "ret" + * result requires three instructions. The second sub is generally only as + * costly as a move instruction and in cases where we compare the result + * with a constant the compiler can fold two constant values and do a + * single instruction, thus saving an instruction overall! + * + * At the worst we save one instruction inside the atomic lock. + */ +static inline int __atomic_sub_return(int i, atomic_t *v) +{ + int ret; + atomic_t *vt = v; + + __atomic_lock_acquire(); + ret = vt->counter; + vt->counter = ret - i; + __atomic_lock_release(); + + return ret - i; +} + +/* + * PUBLIC API FOR ATOMIC! + */ +#define atomic_add(i,v) (__atomic_add( ((int)i),(v))) +#define atomic_sub(i,v) (__atomic_sub( ((int)i),(v))) +#define atomic_inc(v) (__atomic_add( 1,(v))) +#define atomic_dec(v) (__atomic_sub( 1,(v))) +#define atomic_add_return(i,v) (__atomic_add_return( ((int)i),(v))) +#define atomic_sub_return(i,v) (__atomic_sub_return( ((int)i),(v))) +#define atomic_inc_return(v) (__atomic_add_return( 1,(v))) +#define atomic_dec_return(v) (__atomic_sub_return( 1,(v))) +#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) +#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) +#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) +#define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0) + +/* + * atomic_read() + * Acquire the atomic lock and read the variable. + */ +static inline int atomic_read(const atomic_t *v) +{ + int ret; + const atomic_t *vt = v; + + __atomic_lock_acquire(); + ret = vt->counter; + __atomic_lock_release(); + + return ret; +} + +/* + * atomic_set() + * Acquire the atomic lock and set the variable. + */ +static inline void atomic_set(atomic_t *v, int i) +{ + atomic_t *vt = v; + + __atomic_lock_acquire(); + vt->counter = i; + __atomic_lock_release(); +} + +/* + * atomic_cmpxchg + * Acquire the atomic lock and exchange if current == old. + */ +static inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ + int prev; + atomic_t *vt = v; + + __atomic_lock_acquire(); + prev = vt->counter; + if (prev == old) { + vt->counter = new; + } + __atomic_lock_release(); + + return prev; +} + +/* + * atomic_xchg() + * Acquire the atomic lock and exchange values. + */ +static inline int atomic_xchg(atomic_t *v, int new) +{ + int prev; + atomic_t *vt = v; + + __atomic_lock_acquire(); + prev = vt->counter; + vt->counter = new; + __atomic_lock_release(); + + return prev; +} + +/* + * atomic_add_unless() + * Acquire the atomic lock and add a unless the value is u. + */ +static inline int atomic_add_unless(atomic_t *v, int a, int u) +{ + int prev; + atomic_t *vt = v; + + __atomic_lock_acquire(); + prev = vt->counter; + if (prev != u) { + vt->counter += a; + __atomic_lock_release(); + return 1; + } + + __atomic_lock_release(); + return 0; +} + +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) + +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) +#include +#else +#include +#endif + +/* + * The following is not a real function. The compiler should remove the function + * call as long as the user does not pass in a size that __xchg and __cmpxchg + * are not prepared for. If the user does pass in an unknown size, the user + * will get a link time error. + * + * The no return is to prevent a compiler error that can occur when dealing with + * uninitialized variables. Given that the function doesn't exist there is no + * net effect (and if it did it would not return). + */ +extern void __xchg_called_with_bad_pointer(void) __attribute__((noreturn)); + +/* + * __xchg() + * Xchange *ptr for x atomically. + * + * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an + * atomic exchange instruction so we use the global atomic_lock. + */ +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) +{ + unsigned long ret; + + __atomic_lock_acquire(); + + switch (size) { + case 1: + ret = *(volatile unsigned char *)ptr; + *(volatile unsigned char *)ptr = x; + break; + + case 2: + ret = *(volatile unsigned short *)ptr; + *(volatile unsigned short *)ptr = x; + break; + + case 4: + ret = *(volatile unsigned int *)ptr; + *(volatile unsigned int *)ptr = x; + break; + + default: + __xchg_called_with_bad_pointer(); + break; + } + __atomic_lock_release(); + return ret; +} + +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + +/* + * __cmpxchg() + * Compare and Xchange *ptr for x atomically. + * + * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an + * atomic exchange instruction so we use the global atomic_lock. + */ +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long next, int size) +{ + unsigned long prev; + + __atomic_lock_acquire(); + switch (size) { + case 1: + prev = *(u8 *)ptr; + if (prev == old) { + *(u8 *)ptr = (u8)next; + } + break; + + case 2: + prev = *(u16 *)ptr; + if (prev == old) { + *(u16 *)ptr = (u16)next; + } + break; + + case 4: + prev = *(u32 *)ptr; + if (prev == old) { + *(u32 *)ptr = (u32)next; + } + break; + + default: + __xchg_called_with_bad_pointer(); + break; + } + __atomic_lock_release(); + return prev; +} + +/* + * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make + * them available. + */ +#define cmpxchg_local(ptr, o, n) \ + ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), sizeof(*(ptr)))) + +#define cmpxchg(ptr, o, n) __cmpxchg((ptr), (o), (n), sizeof(*(ptr))) + +#define smp_mb__before_atomic_inc() asm volatile ("" : : : "memory") +#define smp_mb__after_atomic_inc() asm volatile ("" : : : "memory") +#define smp_mb__before_atomic_dec() asm volatile ("" : : : "memory") +#define smp_mb__after_atomic_dec() asm volatile ("" : : : "memory") + +#endif /* _ASM_UBICOM32_ATOMIC_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/audio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/audio.h new file mode 100644 index 000000000..974d0cd63 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/audio.h @@ -0,0 +1,40 @@ +/* + * arch/ubicom32/include/asm/audio.h + * Audio include file + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#ifndef _AUDIO_H +#define _AUDIO_H + +#include +#include + +/* + * Resource indices used to access IRQs via platform_get_resource + */ +#define AUDIO_MEM_RESOURCE 0 +#define AUDIO_TX_IRQ_RESOURCE 0 +#define AUDIO_RX_IRQ_RESOURCE 1 + +extern struct platform_device * __init audio_device_alloc(const char *driver_name, const char *node_name, const char *inst_name, int priv_size); + +#define audio_device_priv(pdev) (((struct ubi32pcm_platform_data *)(((struct platform_device *)(pdev))->dev.platform_data))->priv_data) +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/audionode.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/audionode.h new file mode 100644 index 000000000..f18a0e817 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/audionode.h @@ -0,0 +1,152 @@ +/* + * audionode.h + * audionode and DMA descriptors + * + * Copyright © 2009 Ubicom Inc. . All rights reserved. + * + * This file contains confidential information of Ubicom, Inc. and your use of + * this file is subject to the Ubicom Software License Agreement distributed with + * this file. If you are uncertain whether you are an authorized user or to report + * any unauthorized use, please contact Ubicom, Inc. at +1-408-789-2200. + * Unauthorized reproduction or distribution of this file is subject to civil and + * criminal penalties. + * + */ +#ifndef _AUDIONODE_H_ +#define _AUDIONODE_H_ + +#define AUDIO_INT_FLAG_MORE_SAMPLES 0x00000001 +#define AUDIO_INT_FLAG_COMMAND 0x00000002 + +/* + * Commands the Primary OS sends to the audio device + */ +enum audio_command { + AUDIO_CMD_NONE, + AUDIO_CMD_START, + AUDIO_CMD_STOP, + AUDIO_CMD_PAUSE, + AUDIO_CMD_RESUME, + AUDIO_CMD_MUTE, + AUDIO_CMD_UNMUTE, + AUDIO_CMD_SETUP, + AUDIO_CMD_ENABLE, + AUDIO_CMD_DISABLE, +}; + +/* + * Flag bits passed in the registers + */ +#define CMD_START_FLAG_LE (1 << 0) /* Use Little Endian Mode */ + +/* + * Status bits that audio device can set to indicate reason + * for interrupting the Primary OS + */ +#define AUDIO_STATUS_PLAY_DMA0_REQUEST (1 << 0) /* Audio device needs samples in DMA0 for playback */ +#define AUDIO_STATUS_PLAY_DMA1_REQUEST (1 << 1) /* Audio device needs samples in DMA1 for playback */ + +struct audio_dma { + /* + * NOTE: The active flag shall only be SET by the producer and CLEARED + * by the consumer, NEVER the other way around. For playback, the + * Primary OS sets this flag and ipAudio clears it. + * + * The producer shall not modify the ptr or ctr fields when the transfer + * is marked as active, as these are used by the consumer to do the + * transfer. + */ + volatile u32_t active; /* Nonzero if data in ptr/ctr ready to be transferred */ + volatile void *ptr; /* Pointer to data to be transferred */ + volatile u32_t ctr; /* Counter: number of data units to transfer */ +}; + +#define AUDIONODE_CAP_BE (1 << 0) +#define AUDIONODE_CAP_LE (1 << 1) + +#define AUDIONODE_VERSION 7 +struct audio_node { + struct devtree_node dn; + + /* + * Version of this node + */ + u32_t version; + + /* + * Pointer to the registers + */ + struct audio_regs *regs; +}; + +/* + * [OCM] Audio registers + * Registers exposed as part of our MMIO area + */ +#define AUDIO_REGS_VERSION 7 +struct audio_regs { + /* + * Version of this register set + */ + u32_t version; + + /* + * Interrupt status + */ + volatile u32_t int_status; + + /* + * Interrupt request + */ + volatile u32_t int_req; + + /* + * Current IRQ being serviced + */ + u32_t cur_irq; + + /* + * Maximum number of devices supported + */ + u32_t max_devs; + + /* + * [DDR] Device registers for each of the devices + */ + struct audio_dev_regs *adr; +}; + +#define AUDIO_DEV_REGS_VERSION 2 +struct audio_dev_regs { + u32_t version; /* Version of this register set */ + + u8_t name[32]; /* Name of this driver */ + u32_t caps; /* Capabilities of this driver */ + const u32_t *sample_rates; /* Sample Rates supported by this driver */ + u32_t n_sample_rates; /* Number of sample rates supported by this driver */ + u32_t channel_mask; /* A bit set in a particular position means we support this channel configuration */ + volatile u32_t int_flags; /* Reason for interrupting audio device */ + volatile enum audio_command command; /* Command from Primary OS */ + volatile u32_t flags; /* Flag bits for this command */ + volatile u32_t channels; /* Number of channels */ + volatile u32_t sample_rate; /* Sample rate */ + volatile u32_t status; /* Status bits sent from ipAudio to Primary OS */ + void *primary_os_buffer_ptr; /* + * Playback: Pointer to next sample to be removed from + * Primary OS sample buffer + * Capture: Pointer to where next sample will be inserted + * into Primary OS sample buffer + */ + + /* + * These are the transfer requests. They are used in alternating + * order so that when ipAudio is processing one request, the + * Primary OS can fill in the other one. + * + * NOTE: The active bit shall always be SET by the producer and + * CLEARED by the consumer, NEVER the other way around. + */ + struct audio_dma dma_xfer_requests[2]; +}; + +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/auxvec.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/auxvec.h new file mode 100644 index 000000000..b2275c857 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/auxvec.h @@ -0,0 +1,32 @@ +/* + * arch/ubicom32/include/asm/auxvec.h + * Symbolic values for the entries in the auxiliary table + * put on the initial stack. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_AUXVEC_H +#define _ASM_UBICOM32_AUXVEC_H + +#endif /* _ASM_UBICOM32_AUXVEC_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bitops.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bitops.h new file mode 100644 index 000000000..c63837b2e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bitops.h @@ -0,0 +1,172 @@ +/* + * arch/ubicom32/include/asm/bitops.h + * Bit manipulation definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_BITOPS_H +#define _ASM_UBICOM32_BITOPS_H + +/* + * Copyright 1992, Linus Torvalds. + */ + +#include +#include /* swab32 */ + +#ifdef __KERNEL__ + +#ifndef _LINUX_BITOPS_H +#error only can be included directly +#endif + +#include +#include + +#include +#include + +#include + +static inline void set_bit(int bit, volatile unsigned long *p) +{ + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + __atomic_lock_acquire(); + *p |= mask; + __atomic_lock_release(); +} + +static inline void clear_bit(int bit, volatile unsigned long *p) +{ + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + __atomic_lock_acquire(); + *p &= ~mask; + __atomic_lock_release(); +} + +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +static inline void change_bit(int bit, volatile unsigned long *p) +{ + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + __atomic_lock_acquire(); + *p ^= mask; + __atomic_lock_release(); +} + +static inline int test_and_set_bit(int bit, volatile unsigned long *p) +{ + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + __atomic_lock_acquire(); + res = *p; + *p = res | mask; + __atomic_lock_release(); + + return res & mask; +} + +static inline int test_and_clear_bit(int bit, volatile unsigned long *p) +{ + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + __atomic_lock_acquire(); + res = *p; + *p = res & ~mask; + __atomic_lock_release(); + + return res & mask; +} + +static inline int test_and_change_bit(int bit, volatile unsigned long *p) +{ + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + __atomic_lock_acquire(); + res = *p; + *p = res ^ mask; + __atomic_lock_release(); + + return res & mask; +} + +#include + +/* + * This routine doesn't need to be atomic. + */ +static inline int __constant_test_bit(int nr, const volatile unsigned long *addr) +{ + return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; +} + +static inline int __test_bit(int nr, const volatile unsigned long *addr) +{ + int * a = (int *) addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + return ((mask & *a) != 0); +} + +#define test_bit(nr,addr) (__builtin_constant_p(nr) ? __constant_test_bit((nr),(addr)) : __test_bit((nr),(addr))) + +#include +#include +#include + +#include +#include +#include + +#endif /* __KERNEL__ */ + +#include +#include +#include + +#endif /* _ASM_UBICOM32_BITOPS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bitsperlong.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bitsperlong.h new file mode 100644 index 000000000..6dc0bb0c1 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/board.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/board.h new file mode 100644 index 000000000..9df4c0f04 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/board.h @@ -0,0 +1,34 @@ +/* + * arch/ubicom32/include/asm/board.h + * Board init and revision definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_BOARD_H +#define _ASM_UBICOM32_BOARD_H + +extern const char *board_get_revision(void); +extern void __init board_init(void); + +#endif /* _ASM_UBICOM32_BOARD_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootargs.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootargs.h new file mode 100644 index 000000000..95ec393c6 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootargs.h @@ -0,0 +1,34 @@ +/* + * arch/ubicom32/include/asm/bootargs.h + * Kernel command line via the devtree API. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_BOOTARGS_H +#define _ASM_UBICOM32_BOOTARGS_H + +extern const char *bootargs_get_cmdline(void); +extern void __init bootargs_init(void); + +#endif /* _ASM_UBICOM32_BOOTARGS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootinfo.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootinfo.h new file mode 100644 index 000000000..79653911e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootinfo.h @@ -0,0 +1,34 @@ +/* + * arch/ubicom32/include/asm/bootinfo.h + * Definitions of firmware boot parameters passed to the kernel. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_BOOTINFO_H +#define _ASM_UBICOM32_BOOTINFO_H + +/* Nothing for ubicom32 */ + +#endif /* _ASM_UBICOM32_BOOTINFO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bug.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bug.h new file mode 100644 index 000000000..b6a000dac --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bug.h @@ -0,0 +1,95 @@ +/* + * arch/ubicom32/include/asm/bug.h + * Generic bug.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_BUG_H +#define _ASM_UBICOM32_BUG_H + +#include +#include + +#if defined(CONFIG_BUG) && defined(CONFIG_STOP_ON_BUG) + +/* + * BUG() + * Ubicom specific version of the BUG() macro. + * + * This implementation performs a THREAD_STALL stopping all threads before + * calling panic. This enables a developer to see the "real" state of the + * machine (since panic alters the system state). We do the printf first + * because while it is slow, it does not alter system state (like + * interrupts). + * + * TODO: Implement the trap sequence used by other architectures. + */ +#define BUG() do { \ + printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ + THREAD_STALL; \ + panic("BUG!"); \ +} while (0) + + +/* + * __WARN() + * WARN() using printk() for now. + * + * TODO: Implement the trap sequence used by other architectures. + */ +#define __WARN() \ + do { \ + printk("WARN: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ + } while(0) + +/* + * WARN_ON() + * Ubicom specific version of the WARN_ON macro. + * + * This implementation performs a printk for the WARN_ON() instead + * of faulting into the kernel and using report_bug(). + * + * TODO: Implement the trap sequence used by other architectures. + */ +#define WARN_ON(x) ({ \ + int __ret_warn_on = !!(x); \ + if (__builtin_constant_p(__ret_warn_on)) { \ + if (__ret_warn_on) \ + __WARN(); \ + } else { \ + if (unlikely(__ret_warn_on)) \ + __WARN(); \ + } \ + unlikely(__ret_warn_on); \ +}) + + +#define HAVE_ARCH_BUG +#define HAVE_ARCH_WARN_ON + +#endif + +#include + +#endif /* _ASM_UBICOM32_BUG_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bugs.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bugs.h new file mode 100644 index 000000000..66adfe7b0 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bugs.h @@ -0,0 +1,44 @@ +/* + * arch/ubicom32/include/asm/bugs.h + * Definition of check_bugs() for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1994 Linus Torvalds + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +/* + * This is included by init/main.c to check for architecture-dependent bugs. + * + * Needs: + * void check_bugs(void); + */ + +#ifndef _ASM_UBICOM32_BUGS_H +#define _ASM_UBICOM32_BUGS_H + +static void check_bugs(void) +{ +} + +#endif /* _ASM_UBICOM32_BUGS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/byteorder.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/byteorder.h new file mode 100644 index 000000000..e4cd7c92f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/byteorder.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/byteorder.h + * Byte order swapping utility routines. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_BYTEORDER_H +#define _ASM_UBICOM32_BYTEORDER_H + +#include + +#endif /* _ASM_UBICOM32_BYTEORDER_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cache.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cache.h new file mode 100644 index 000000000..5fcd36db7 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cache.h @@ -0,0 +1,40 @@ +/* + * arch/ubicom32/include/asm/cache.h + * Cache line definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_CACHE_H +#define _ASM_UBICOM32_CACHE_H + +/* + * bytes per L1 cache line + */ +#define L1_CACHE_SHIFT 5 +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#define __cacheline_aligned +#define ____cacheline_aligned + +#endif /* _ASM_UBICOM32_CACHE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cachectl.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cachectl.h new file mode 100644 index 000000000..12a9159e5 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cachectl.h @@ -0,0 +1,39 @@ +/* + * arch/ubicom32/include/asm/cachectl.h + * Ubicom32 cache control definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_CACHECTL_H +#define _ASM_UBICOM32_CACHECTL_H + +#include + +/* + * mem_cache_control() + * Special cache control operation + */ +extern void mem_cache_control(unsigned long cc, unsigned long begin_addr, unsigned long end_addr, unsigned long op); + +#endif /* _ASM_UBICOM32_CACHECTL_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cacheflush.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cacheflush.h new file mode 100644 index 000000000..10a8141e5 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cacheflush.h @@ -0,0 +1,111 @@ +/* + * arch/ubicom32/include/asm/cacheflush.h + * Cache flushing definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_CACHEFLUSH_H +#define _ASM_UBICOM32_CACHEFLUSH_H + +/* + * (C) Copyright 2000-2004, Greg Ungerer + */ +#include +#include +#include + +#define flush_cache_all() __flush_cache_all() +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_dup_mm(mm) do { } while (0) +#define flush_cache_range(vma, start, end) __flush_cache_all() +#define flush_cache_page(vma, vmaddr) do { } while (0) +#define flush_dcache_page(page) do { } while (0) +#define flush_dcache_mmap_lock(mapping) do { } while (0) +#define flush_dcache_mmap_unlock(mapping) do { } while (0) + +#define flush_dcache_range(start, end) \ +do { \ + /* Flush the data cache and invalidate the I cache. */ \ + mem_cache_control(DCCR_BASE, start, end, CCR_CTRL_FLUSH_ADDR); \ + mem_cache_control(ICCR_BASE, start, end, CCR_CTRL_INV_ADDR); \ +} while (0) + +#define flush_icache_range(start, end) \ +do { \ + /* Flush the data cache and invalidate the I cache. */ \ + mem_cache_control(DCCR_BASE, start, end, CCR_CTRL_FLUSH_ADDR); \ + mem_cache_control(ICCR_BASE, start, end, CCR_CTRL_INV_ADDR); \ +} while (0) + +#define flush_icache_page(vma,pg) do { } while (0) +#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) +#define flush_cache_vmap(start, end) do { } while (0) +#define flush_cache_vunmap(start, end) do { } while (0) + +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ + memcpy(dst, src, len) +#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ + memcpy(dst, src, len) + +/* + * Cache handling for IP5000 + */ +extern inline void mem_cache_invalidate_all(unsigned long cc) +{ + if (cc == DCCR_BASE) + UBICOM32_LOCK(DCCR_LOCK_BIT); + else + UBICOM32_LOCK(ICCR_LOCK_BIT); + + asm volatile ( + " bset "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_RESET)" \n\t" + " nop \n\t" + " bclr "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_RESET)" \n\t" + " pipe_flush 0 \n\t" + : + : "a"(cc) + : "cc" + ); + + if (cc == DCCR_BASE) + UBICOM32_UNLOCK(DCCR_LOCK_BIT); + else + UBICOM32_UNLOCK(ICCR_LOCK_BIT); + +} + +static inline void __flush_cache_all(void) +{ + /* + * Flush Icache + */ + mem_cache_invalidate_all(ICCR_BASE); + + /* + * Flush Dcache + */ + mem_cache_invalidate_all(DCCR_BASE); +} + +#endif /* _ASM_UBICOM32_CACHEFLUSH_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/checksum.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/checksum.h new file mode 100644 index 000000000..25f8ca61c --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/checksum.h @@ -0,0 +1,149 @@ +/* + * arch/ubicom32/include/asm/checksum.h + * Checksum utilities for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_CHECKSUM_H +#define _ASM_UBICOM32_CHECKSUM_H + +#include + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +__wsum csum_partial(const void *buff, int len, __wsum sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +__wsum csum_partial_copy_nocheck(const void *src, void *dst, + int len, __wsum sum); + + +/* + * the same as csum_partial_copy, but copies from user space. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +extern __wsum csum_partial_copy_from_user(const void __user *src, + void *dst, int len, __wsum sum, int *csum_err); + +__sum16 ip_fast_csum(const void *iph, unsigned int ihl); + +/* + * Fold a partial checksum + */ + +static inline __sum16 csum_fold(__wsum sum) +{ + asm volatile ( + " lsr.4 d15, %0, #16 \n\t" + " bfextu %0, %0, #16 \n\t" + " add.4 %0, d15, %0 \n\t" + " lsr.4 d15, %0, #16 \n\t" + " bfextu %0, %0, #16 \n\t" + " add.4 %0, d15, %0 \n\t" + : "=&d" (sum) + : "0"(sum) + : "d15" + ); + return (__force __sum16)~sum; +} + + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ + +static inline __wsum +csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, + unsigned short proto, __wsum sum) +{ + asm volatile ( + " add.4 %0, %2, %0 \n\t" + " addc %0, %3, %0 \n\t" + " addc %0, %4, %0 \n\t" + " addc %0, %5, %0 \n\t" + " addc %0, #0, %0 \n\t" + : "=&d" (sum) + : "0"(sum), "r" (saddr), "r" (daddr), "r" (len), "r"(proto) + ); + return sum; +} + +static inline __sum16 +csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len, + unsigned short proto, __wsum sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +extern __sum16 ip_compute_csum(const void *buff, int len); + +#define _HAVE_ARCH_IPV6_CSUM + +static __inline__ __sum16 +csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr, + __u32 len, unsigned short proto, __wsum sum) +{ + asm volatile ( + " add.4 %0, 0(%2), %0 \n\t" + " addc %0, 4(%2), %0 \n\t" + " addc %0, 8(%2), %0 \n\t" + " addc %0, 12(%2), %0 \n\t" + " addc %0, 0(%3), %0 \n\t" + " addc %0, 4(%3), %0 \n\t" + " addc %0, 8(%3), %0 \n\t" + " addc %0, 12(%3), %0 \n\t" + " addc %0, %4, %0 \n\t" + " addc %0, #0, %0 \n\t" + : "=&d" (sum) + : "0" (sum), "a" (saddr), "a" (daddr), "d" (len + proto) + ); + return csum_fold(sum); +} + +#endif /* _ASM_UBICOM32_CHECKSUM_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cpu.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cpu.h new file mode 100644 index 000000000..c713b6253 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cpu.h @@ -0,0 +1,45 @@ +/* + * arch/ubicom32/include/asm/cpu.h + * CPU definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2004-2005 ARM Ltd. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_CPU_H +#define _ASM_UBICOM32_CPU_H + +#include + +struct cpuinfo_ubicom32 { + unsigned long tid; /* Hardware thread number */ + +#ifdef CONFIG_SMP + volatile unsigned long ipi_pending; /* Bit map of operations to execute */ + unsigned long ipi_count; /* Number of IPI(s) taken on this cpu */ +#endif +}; + +DECLARE_PER_CPU(struct cpuinfo_ubicom32, cpu_data); + +#endif /* _ASM_UBICOM32_CPU_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cputime.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cputime.h new file mode 100644 index 000000000..c79444342 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cputime.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/cputime.h + * Generic cputime.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_CPUTIME_H +#define _ASM_UBICOM32_CPUTIME_H + +#include + +#endif /* _ASM_UBICOM32_CPUTIME_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/current.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/current.h new file mode 100644 index 000000000..2d549bbf7 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/current.h @@ -0,0 +1,44 @@ +/* + * arch/ubicom32/include/asm/current.h + * Definition of get_current() for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * (C) Copyright 2000, Lineo, David McCullough + * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_CURRENT_H +#define _ASM_UBICOM32_CURRENT_H + +#include + +struct task_struct; + +static inline struct task_struct *get_current(void) +{ + return(current_thread_info()->task); +} + +#define current get_current() + +#endif /* _ASM_UBICOM32_CURRENT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/delay.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/delay.h new file mode 100644 index 000000000..0e5025c46 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/delay.h @@ -0,0 +1,75 @@ +/* + * arch/ubicom32/include/asm/delay.h + * Definition of delay routines for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_DELAY_H +#define _ASM_UBICOM32_DELAY_H + +#include +#include + +static inline void __delay(unsigned long loops) +{ + if (loops == 0) { + return; + } + + asm volatile ( + "1: add.4 %0, #-1, %0 \n\t" + " jmpne.t 1b \n\t" + : "+d" (loops) + ); +} + +/* + * Ubicom32 processor uses fixed 12MHz external OSC. + * So we use that as reference to count 12 cycles/us + */ + +extern unsigned long loops_per_jiffy; + +static inline void _udelay(unsigned long usecs) +{ +#if defined(CONFIG_UBICOM32_V4) || defined(CONFIG_UBICOM32_V3) + asm volatile ( + " add.4 d15, 0(%0), %1 \n\t" + " sub.4 #0, 0(%0), d15 \n\t" + " jmpmi.w.f .-4 \n\t" + : + : "a"(TIMER_BASE + TIMER_MPTVAL), "d"(usecs * (12000000/1000000)) + : "d15" + ); +#else + BUG(); +#endif +} + +/* + * Moved the udelay() function into library code, no longer inlined. + */ +extern void udelay(unsigned long usecs); + +#endif /* _ASM_UBICOM32_DELAY_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/device.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/device.h new file mode 100644 index 000000000..53de082b0 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/device.h @@ -0,0 +1,35 @@ +/* + * arch/ubicom32/include/asm/device.h + * Generic device.h for Ubicom32 architecture. + * + * Used for arch specific extensions to struct device + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_DEVICE_H +#define _ASM_UBICOM32_DEVICE_H + +#include + +#endif /* _ASM_UBICOM32_DEVICE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/devtree.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/devtree.h new file mode 100644 index 000000000..3380c2bea --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/devtree.h @@ -0,0 +1,52 @@ +/* + * arch/ubicom32/include/asm/devtree.h + * Device Tree Header File (Shared between ultra and the Host OS) + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_DEVTREE_H +#define _ASM_UBICOM32_DEVTREE_H + +#define DEVTREE_MAX_NAME 32 +#define DEVTREE_IRQ_NONE 0xff +#define DEVTREE_IRQ_DONTCARE 0xff +#define DEVTREE_NODE_MAGIC 0x10203040 + +struct devtree_node { + struct devtree_node *next; + unsigned char sendirq; + unsigned char recvirq; + char name[DEVTREE_MAX_NAME]; + unsigned int magic; +}; + +extern struct devtree_node *devtree; +extern struct devtree_node *devtree_find_by_irq(uint8_t sendirq, uint8_t recvirq); +extern struct devtree_node *devtree_find_node(const char *str); +extern struct devtree_node *devtree_find_next(struct devtree_node **cur); +extern int devtree_irq(struct devtree_node *dn, unsigned char *sendirq, unsigned char *recvirq); +extern void devtree_print(void); + +#endif /* _ASM_UBICOM32_DEVTREE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/div64.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/div64.h new file mode 100644 index 000000000..97702617b --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/div64.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/div64.h + * Generic div64.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_DIV64_H +#define _ASM_UBICOM32_DIV64_H + +#include + +#endif /* _ASM_UBICOM32_DIV64_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma-mapping.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma-mapping.h new file mode 100644 index 000000000..87639a429 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma-mapping.h @@ -0,0 +1,328 @@ +/* + * arch/ubicom32/include/asm/dma-mapping.h + * Generic dma-mapping.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_DMA_MAPPING_H +#define _ASM_UBICOM32_DMA_MAPPING_H + +#include +#ifdef CONFIG_PCI + +/* we implement the API below in terms of the existing PCI one, + * so include it */ +#include +/* need struct page definitions */ +#include + +static inline int +dma_supported(struct device *dev, u64 mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_dma_supported(to_pci_dev(dev), mask); +} + +static inline int +dma_set_mask(struct device *dev, u64 dma_mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_set_dma_mask(to_pci_dev(dev), dma_mask); +} + +static inline void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t flag) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); +} + +static inline void +dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); +} + +static inline dma_addr_t +dma_map_single(struct device *dev, void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); +} + +static inline void +dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); +} + +static inline dma_addr_t +dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); +} + +static inline void +dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); +} + +static inline int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); +} + +static inline void +dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); +} + +static inline void +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, + size, (int)direction); +} + +static inline void +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, + size, (int)direction); +} + +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); +} + +static inline void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); +} + +static inline int +dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return pci_dma_mapping_error(to_pci_dev(dev), dma_addr); +} + + +#else + +static inline int +dma_supported(struct device *dev, u64 mask) +{ + return 0; +} + +static inline int +dma_set_mask(struct device *dev, u64 dma_mask) +{ + BUG(); + return 0; +} + +static inline void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t flag) +{ + BUG(); + return NULL; +} + +static inline void +dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + BUG(); +} + +static inline dma_addr_t +dma_map_single(struct device *dev, void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + BUG(); + return 0; +} + +static inline void +dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline dma_addr_t +dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG(); + return 0; +} + +static inline void +dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + BUG(); + return 0; +} + +static inline void +dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline int +dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return 0; +} + +#endif + +/* Now for the API extensions over the pci_ one */ + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(d, h) (1) + +static inline int +dma_get_cache_alignment(void) +{ + /* no easy way to get cache size on all processors, so return + * the maximum possible, to be safe */ + return (1 << INTERNODE_CACHE_SHIFT); +} + +static inline void +dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + /* just sync everything, that's all the pci API can do */ + dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction); +} + +static inline void +dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + /* just sync everything, that's all the pci API can do */ + dma_sync_single_for_device(dev, dma_handle, offset+size, direction); +} + +static inline void +dma_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction direction) +{ + /* could define this in terms of the dma_cache ... operations, + * but if you get this on a platform, you should convert the platform + * to using the generic device DMA API */ + BUG(); +} + +#endif /* _ASM_UBICOM32_DMA_MAPPING_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma.h new file mode 100644 index 000000000..c3a10acf9 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma.h @@ -0,0 +1,34 @@ +/* + * arch/ubicom32/include/asm/dma.h + * DMA definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_DMA_H +#define _ASM_UBICOM32_DMA_H + +/* Nothing so far */ +#define MAX_DMA_ADDRESS 0x00 /* This is quite suspicious */ + +#endif /* _ASM_UBICOM32_DMA_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/elf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/elf.h new file mode 100644 index 000000000..3abc202ac --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/elf.h @@ -0,0 +1,173 @@ +/* + * arch/ubicom32/include/asm/elf.h + * Definitions for elf executable format for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_ELF_H +#define _ASM_UBICOM32_ELF_H + +/* + * ELF register definitions.. + */ + +#include +#include + +/* + * Processor specific flags for the ELF header e_flags field. + */ +#define EF_UBICOM32_V3 0x00000001 /* -fmarch=ubicom32v3 */ +#define EF_UBICOM32_V4 0x00000002 /* -fmarch=ubicom32v4 */ +#define EF_UBICOM32_PIC 0x80000000 /* -fpic */ +#define EF_UBICOM32_FDPIC 0x40000000 /* -mfdpic */ + +/* + * Ubicom32 ELF relocation types + */ +#define R_UBICOM32_NONE 0 +#define R_UBICOM32_16 1 +#define R_UBICOM32_32 2 +#define R_UBICOM32_LO16 3 +#define R_UBICOM32_HI16 4 +#define R_UBICOM32_21_PCREL 5 +#define R_UBICOM32_24_PCREL 6 +#define R_UBICOM32_HI24 7 +#define R_UBICOM32_LO7_S 8 +#define R_UBICOM32_LO7_2_S 9 +#define R_UBICOM32_LO7_4_S 10 +#define R_UBICOM32_LO7_D 11 +#define R_UBICOM32_LO7_2_D 12 +#define R_UBICOM32_LO7_4_D 13 +#define R_UBICOM32_32_HARVARD 14 +#define R_UBICOM32_LO7_CALLI 15 +#define R_UBICOM32_LO16_CALLI 16 +#define R_UBICOM32_GOT_HI24 17 +#define R_UBICOM32_GOT_LO7_S 18 +#define R_UBICOM32_GOT_LO7_2_S 19 +#define R_UBICOM32_GOT_LO7_4_S 20 +#define R_UBICOM32_GOT_LO7_D 21 +#define R_UBICOM32_GOT_LO7_2_D 22 +#define R_UBICOM32_GOT_LO7_4_D 23 +#define R_UBICOM32_FUNCDESC_GOT_HI24 24 +#define R_UBICOM32_FUNCDESC_GOT_LO7_S 25 +#define R_UBICOM32_FUNCDESC_GOT_LO7_2_S 26 +#define R_UBICOM32_FUNCDESC_GOT_LO7_4_S 27 +#define R_UBICOM32_FUNCDESC_GOT_LO7_D 28 +#define R_UBICOM32_FUNCDESC_GOT_LO7_2_D 29 +#define R_UBICOM32_FUNCDESC_GOT_LO7_4_D 30 +#define R_UBICOM32_GOT_LO7_CALLI 31 +#define R_UBICOM32_FUNCDESC_GOT_LO7_CALLI 32 +#define R_UBICOM32_FUNCDESC_VALUE 33 +#define R_UBICOM32_FUNCDESC 34 +#define R_UBICOM32_GOTOFFSET_LO 35 +#define R_UBICOM32_GOTOFFSET_HI 36 +#define R_UBICOM32_FUNCDESC_GOTOFFSET_LO 37 +#define R_UBICOM32_FUNCDESC_GOTOFFSET_HI 38 +#define R_UBICOM32_GNU_VTINHERIT 200 +#define R_UBICOM32_GNU_VTENTRY 201 + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_ubicom32fp_struct elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x)->e_machine == EM_UBICOM32) + +#define elf_check_fdpic(x) ((x)->e_flags & EF_UBICOM32_FDPIC) + +#define elf_check_const_displacement(x) ((x)->e_flags & EF_UBICOM32_PIC) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_UBICOM32 + +/* For SVR4/m68k the function pointer to be registered with `atexit' is + passed in %a1. Although my copy of the ABI has no such statement, it + is actually used on ASV. */ +#define ELF_PLAT_INIT(_r, load_addr) _r->a1 = 0 + +#define ELF_FDPIC_PLAT_INIT(_regs, _exec_map_addr, _interp_map_addr, \ + _dynamic_addr) \ + do { \ + _regs->dn[1] = _exec_map_addr; \ + _regs->dn[2] = _interp_map_addr; \ + _regs->dn[3] = _dynamic_addr; \ + _regs->an[1] = 0; /* dl_fini will be set by ldso */ \ + } while (0) + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#ifdef __KERNEL__ +#ifdef CONFIG_UBICOM32_V4 +#define ELF_FDPIC_CORE_EFLAGS (EF_UBICOM32_FDPIC | EF_UBICOM32_V4) +#elif defined CONFIG_UBICOM32_V3 +#define ELF_FDPIC_CORE_EFLAGS (EF_UBICOM32_FDPIC | EF_UBICOM32_V3) +#else +#error Unknown/Unsupported ubicom32 architecture. +#endif +#endif + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE 0xD0000000UL + +/* + * For Ubicom32, the elf_gregset_t and struct pt_regs are the same size + * data structure so a copy is performed instead of providing the + * ELF_CORE_COPY_REGS macro. + */ + +/* + * ELF_CORE_COPY_TASK_REGS is needed to dump register state from multi threaded user projects. + */ +extern int dump_task_regs(struct task_struct *, elf_gregset_t *); +#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs) + +/* This yields a mask that user programs can use to figure out what + instruction set this cpu supports. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. */ + +#define ELF_PLATFORM (NULL) + +#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) + +#endif /* _ASM_UBICOM32_ELF_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/emergency-restart.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/emergency-restart.h new file mode 100644 index 000000000..ea39e58ce --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/emergency-restart.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/emergency-restart.h + * Generic emergency-restart.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_EMERGENCY_RESTART_H +#define _ASM_UBICOM32_EMERGENCY_RESTART_H + +#include + +#endif /* _ASM_UBICOM32_EMERGENCY_RESTART_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/entry.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/entry.h new file mode 100644 index 000000000..5ef46e62d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/entry.h @@ -0,0 +1,34 @@ +/* + * arch/ubicom32/include/asm/entry.h + * Entry register/stack definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_ENTRY_H +#define _ASM_UBICOM32_ENTRY_H + +#include +#include + +#endif /* _ASM_UBICOM32_ENTRY_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/errno.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/errno.h new file mode 100644 index 000000000..bf995b16a --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/errno.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/errno.h + * Generic errno.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_ERRNO_H +#define _ASM_UBICOM32_ERRNO_H + +#include + +#endif /* _ASM_UBICOM32_ERRNO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/fb.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/fb.h new file mode 100644 index 000000000..9e9cc6bc7 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/fb.h @@ -0,0 +1,39 @@ +/* + * arch/ubicom32/include/asm/fb.h + * Definition of fb_is_primary_device() for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_FB_H +#define _ASM_UBICOM32_FB_H +#include + +#define fb_pgprotect(...) do {} while (0) + +static inline int fb_is_primary_device(struct fb_info *info) +{ + return 0; +} + +#endif /* _ASM_UBICOM32_FB_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/fcntl.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/fcntl.h new file mode 100644 index 000000000..810638c57 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/fcntl.h @@ -0,0 +1,38 @@ +/* + * arch/ubicom32/include/asm/fcntl.h + * File control bit definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_FCNTL_H +#define _ASM_UBICOM32_FCNTL_H + +#define O_DIRECTORY 040000 /* must be a directory */ +#define O_NOFOLLOW 0100000 /* don't follow links */ +#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ +#define O_LARGEFILE 0400000 + +#include + +#endif /* _ASM_UBICOM32_FCNTL_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/flat.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/flat.h new file mode 100644 index 000000000..84edd478b --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/flat.h @@ -0,0 +1,73 @@ +/* + * arch/ubicom32/include/asm/flat.h + * Definitions to support flat-format executables. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_FLAT_H +#define _ASM_UBICOM32_FLAT_H + +#define ARCH_FLAT_ALIGN 0x80 +#define ARCH_FLAT_ALIGN_TEXT 1 + +#define R_UBICOM32_32 2 +#define R_UBICOM32_HI24 7 +#define R_UBICOM32_LO7_S 8 +#define R_UBICOM32_LO7_2_S 9 +#define R_UBICOM32_LO7_4_S 10 +#define R_UBICOM32_LO7_D 11 +#define R_UBICOM32_LO7_2_D 12 +#define R_UBICOM32_LO7_4_D 13 +#define R_UBICOM32_LO7_CALLI 15 +#define R_UBICOM32_LO16_CALLI 16 + +extern void ubicom32_flat_put_addr_at_rp(unsigned long *rp, u32_t val, u32_t rval, unsigned long *p); +extern unsigned long ubicom32_flat_get_addr_from_rp(unsigned long *rp, u32_t relval, u32_t flags, unsigned long *p); + +#define flat_stack_align(sp) /* nothing needed */ +#define flat_argvp_envp_on_stack() 1 +#define flat_old_ram_flag(flags) (flags) +#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) +#define flat_get_addr_from_rp(rp, relval, flags, p) (ubicom32_flat_get_addr_from_rp(rp, relval,flags, p)) +#define flat_put_addr_at_rp(rp, val, relval) do {ubicom32_flat_put_addr_at_rp(rp, val, relval, &persistent);} while(0) +#define flat_get_relocate_addr(rel) ((persistent) ? (persistent & 0x07ffffff) : (rel & 0x07ffffff)) + +static inline int flat_set_persistent(unsigned int relval, unsigned long *p) +{ + if (*p) { + return 0; + } else { + if ((relval >> 27) != R_UBICOM32_32) { + /* + * Something other than UBICOM32_32. The next entry has the relocation. + */ + *p = relval; + return 1; + } + } + return 0; +} + +#endif /* _ASM_UBICOM32_FLAT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/fpu.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/fpu.h new file mode 100644 index 000000000..496b7ddc3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/fpu.h @@ -0,0 +1,37 @@ +/* + * arch/ubicom32/include/asm/fpu.h + * Floating point state definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_FPU_H +#define _ASM_UBICOM32_FPU_H + +/* + * MAX floating point unit state size (FSAVE/FRESTORE) + */ +/* No FP unit present then... */ +#define FPSTATESIZE (2) /* dummy size */ + +#endif /* _ASM_UBICOM32_FPU_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ftrace.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ftrace.h new file mode 100644 index 000000000..40a8c178f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ftrace.h @@ -0,0 +1 @@ +/* empty */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/futex.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/futex.h new file mode 100644 index 000000000..8c84b31f3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/futex.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/futex.h + * Generic futex.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_FUTEX_H +#define _ASM_UBICOM32_FUTEX_H + +#include + +#endif /* _ASM_UBICOM32_FUTEX_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/gpio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/gpio.h new file mode 100644 index 000000000..1f834f35b --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/gpio.h @@ -0,0 +1,453 @@ +/* + * arch/ubicom32/include/asm/gpio.h + * Definitions for GPIO operations on Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_GPIO_H +#define _ASM_UBICOM32_GPIO_H + +#include +#include + +#include + +#define ARCH_NR_GPIOS 512 +#define MAX_UBICOM_ONCHIP_GPIO (9 * 32) + +/* + * Macros for manipulating GPIO numbers + */ +#define gpio_bit(gn) (1 << (gn & 0x1f)) +#define gpio_bank(gn) (gn >> 5) + +#define gpio_pin_index(gn) (gn & 0x1f) +#define gpio_port_index(gn) (gn >> 5) + +#define GPIO_RA_0 ((32 * 0) + 0) +#define GPIO_RA_1 ((32 * 0) + 1) +#define GPIO_RA_2 ((32 * 0) + 2) +#define GPIO_RA_3 ((32 * 0) + 3) +#define GPIO_RA_4 ((32 * 0) + 4) +#define GPIO_RA_5 ((32 * 0) + 5) +#define GPIO_RA_6 ((32 * 0) + 6) +#define GPIO_RA_7 ((32 * 0) + 7) + +#define GPIO_RB_0 ((32 * 1) + 0) +#define GPIO_RB_1 ((32 * 1) + 1) +#define GPIO_RB_2 ((32 * 1) + 2) +#define GPIO_RB_3 ((32 * 1) + 3) +#define GPIO_RB_4 ((32 * 1) + 4) +#define GPIO_RB_5 ((32 * 1) + 5) +#define GPIO_RB_6 ((32 * 1) + 6) +#define GPIO_RB_7 ((32 * 1) + 7) +#define GPIO_RB_8 ((32 * 1) + 8) +#define GPIO_RB_9 ((32 * 1) + 9) +#define GPIO_RB_10 ((32 * 1) + 10) +#define GPIO_RB_11 ((32 * 1) + 11) +#define GPIO_RB_12 ((32 * 1) + 12) +#define GPIO_RB_13 ((32 * 1) + 13) +#define GPIO_RB_14 ((32 * 1) + 14) +#define GPIO_RB_15 ((32 * 1) + 15) +#define GPIO_RB_16 ((32 * 1) + 16) +#define GPIO_RB_17 ((32 * 1) + 17) +#define GPIO_RB_18 ((32 * 1) + 18) +#define GPIO_RB_19 ((32 * 1) + 19) + +#define GPIO_RC_0 ((32 * 2) + 0) +#define GPIO_RC_1 ((32 * 2) + 1) +#define GPIO_RC_2 ((32 * 2) + 2) +#define GPIO_RC_3 ((32 * 2) + 3) +#define GPIO_RC_4 ((32 * 2) + 4) +#define GPIO_RC_5 ((32 * 2) + 5) +#define GPIO_RC_6 ((32 * 2) + 6) +#define GPIO_RC_7 ((32 * 2) + 7) +#define GPIO_RC_8 ((32 * 2) + 8) +#define GPIO_RC_9 ((32 * 2) + 9) +#define GPIO_RC_10 ((32 * 2) + 10) +#define GPIO_RC_11 ((32 * 2) + 11) +#define GPIO_RC_12 ((32 * 2) + 12) +#define GPIO_RC_13 ((32 * 2) + 13) +#define GPIO_RC_14 ((32 * 2) + 14) +#define GPIO_RC_15 ((32 * 2) + 15) +#define GPIO_RC_16 ((32 * 2) + 16) +#define GPIO_RC_17 ((32 * 2) + 17) +#define GPIO_RC_18 ((32 * 2) + 18) +#define GPIO_RC_19 ((32 * 2) + 19) +#define GPIO_RC_20 ((32 * 2) + 20) +#define GPIO_RC_21 ((32 * 2) + 21) +#define GPIO_RC_22 ((32 * 2) + 22) +#define GPIO_RC_23 ((32 * 2) + 23) +#define GPIO_RC_24 ((32 * 2) + 24) +#define GPIO_RC_25 ((32 * 2) + 25) +#define GPIO_RC_26 ((32 * 2) + 26) +#define GPIO_RC_27 ((32 * 2) + 27) +#define GPIO_RC_28 ((32 * 2) + 28) +#define GPIO_RC_29 ((32 * 2) + 29) +#define GPIO_RC_30 ((32 * 2) + 30) +#define GPIO_RC_31 ((32 * 2) + 31) + +#define GPIO_RD_0 ((32 * 3) + 0) +#define GPIO_RD_1 ((32 * 3) + 1) +#define GPIO_RD_2 ((32 * 3) + 2) +#define GPIO_RD_3 ((32 * 3) + 3) +#define GPIO_RD_4 ((32 * 3) + 4) +#define GPIO_RD_5 ((32 * 3) + 5) +#define GPIO_RD_6 ((32 * 3) + 6) +#define GPIO_RD_7 ((32 * 3) + 7) +#define GPIO_RD_8 ((32 * 3) + 8) +#define GPIO_RD_9 ((32 * 3) + 9) +#define GPIO_RD_10 ((32 * 3) + 10) +#define GPIO_RD_11 ((32 * 3) + 11) + +#define GPIO_RE_0 ((32 * 4) + 0) +#define GPIO_RE_1 ((32 * 4) + 1) +#define GPIO_RE_2 ((32 * 4) + 2) +#define GPIO_RE_3 ((32 * 4) + 3) +#define GPIO_RE_4 ((32 * 4) + 4) +#define GPIO_RE_5 ((32 * 4) + 5) +#define GPIO_RE_6 ((32 * 4) + 6) +#define GPIO_RE_7 ((32 * 4) + 7) + +#define GPIO_RF_0 ((32 * 5) + 0) +#define GPIO_RF_1 ((32 * 5) + 1) +#define GPIO_RF_2 ((32 * 5) + 2) +#define GPIO_RF_3 ((32 * 5) + 3) +#define GPIO_RF_4 ((32 * 5) + 4) +#define GPIO_RF_5 ((32 * 5) + 5) +#define GPIO_RF_6 ((32 * 5) + 6) +#define GPIO_RF_7 ((32 * 5) + 7) +#define GPIO_RF_8 ((32 * 5) + 8) +#define GPIO_RF_9 ((32 * 5) + 9) +#define GPIO_RF_10 ((32 * 5) + 10) +#define GPIO_RF_11 ((32 * 5) + 11) +#define GPIO_RF_12 ((32 * 5) + 12) +#define GPIO_RF_13 ((32 * 5) + 13) +#define GPIO_RF_14 ((32 * 5) + 14) +#define GPIO_RF_15 ((32 * 5) + 15) + +#define GPIO_RG_0 ((32 * 6) + 0) +#define GPIO_RG_1 ((32 * 6) + 1) +#define GPIO_RG_2 ((32 * 6) + 2) +#define GPIO_RG_3 ((32 * 6) + 3) +#define GPIO_RG_4 ((32 * 6) + 4) +#define GPIO_RG_5 ((32 * 6) + 5) +#define GPIO_RG_6 ((32 * 6) + 6) +#define GPIO_RG_7 ((32 * 6) + 7) +#define GPIO_RG_8 ((32 * 6) + 8) +#define GPIO_RG_9 ((32 * 6) + 9) +#define GPIO_RG_10 ((32 * 6) + 10) +#define GPIO_RG_11 ((32 * 6) + 11) +#define GPIO_RG_12 ((32 * 6) + 12) +#define GPIO_RG_13 ((32 * 6) + 13) +#define GPIO_RG_14 ((32 * 6) + 14) +#define GPIO_RG_15 ((32 * 6) + 15) +#define GPIO_RG_16 ((32 * 6) + 16) +#define GPIO_RG_17 ((32 * 6) + 17) +#define GPIO_RG_18 ((32 * 6) + 18) +#define GPIO_RG_19 ((32 * 6) + 19) +#define GPIO_RG_20 ((32 * 6) + 20) +#define GPIO_RG_21 ((32 * 6) + 21) +#define GPIO_RG_22 ((32 * 6) + 22) +#define GPIO_RG_23 ((32 * 6) + 23) +#define GPIO_RG_24 ((32 * 6) + 24) +#define GPIO_RG_25 ((32 * 6) + 25) +#define GPIO_RG_26 ((32 * 6) + 26) +#define GPIO_RG_27 ((32 * 6) + 27) +#define GPIO_RG_28 ((32 * 6) + 28) +#define GPIO_RG_29 ((32 * 6) + 29) +#define GPIO_RG_30 ((32 * 6) + 30) +#define GPIO_RG_31 ((32 * 6) + 31) + +#define GPIO_RH_0 ((32 * 7) + 0) +#define GPIO_RH_1 ((32 * 7) + 1) +#define GPIO_RH_2 ((32 * 7) + 2) +#define GPIO_RH_3 ((32 * 7) + 3) +#define GPIO_RH_4 ((32 * 7) + 4) +#define GPIO_RH_5 ((32 * 7) + 5) +#define GPIO_RH_6 ((32 * 7) + 6) +#define GPIO_RH_7 ((32 * 7) + 7) +#define GPIO_RH_8 ((32 * 7) + 8) +#define GPIO_RH_9 ((32 * 7) + 9) + +#define GPIO_RI_0 ((32 * 8) + 0) +#define GPIO_RI_1 ((32 * 8) + 1) +#define GPIO_RI_2 ((32 * 8) + 2) +#define GPIO_RI_3 ((32 * 8) + 3) +#define GPIO_RI_4 ((32 * 8) + 4) +#define GPIO_RI_5 ((32 * 8) + 5) +#define GPIO_RI_6 ((32 * 8) + 6) +#define GPIO_RI_7 ((32 * 8) + 7) +#define GPIO_RI_8 ((32 * 8) + 8) +#define GPIO_RI_9 ((32 * 8) + 9) +#define GPIO_RI_10 ((32 * 8) + 10) +#define GPIO_RI_11 ((32 * 8) + 11) +#define GPIO_RI_12 ((32 * 8) + 12) +#define GPIO_RI_13 ((32 * 8) + 13) +#define GPIO_RI_14 ((32 * 8) + 14) +#define GPIO_RI_15 ((32 * 8) + 15) + +/* + * The following section defines extra GPIO available to some boards. + * These GPIO are generally external to the processor (i.e. SPI/I2C + * expander chips). + * + * Note that these defines show all possible GPIO available, however, + * depending on the actual board configuration, some GPIO are not + * available for use. + */ +#ifdef CONFIG_IP7500MEDIA +/* + * U15 + */ +#define IP7500MEDIA_U15_BASE (32 * 10) +#define IP7500MEDIA_IO0 (IP7500MEDIA_U15_BASE + 0) +#define IP7500MEDIA_IO1 (IP7500MEDIA_U15_BASE + 1) +#define IP7500MEDIA_IO2 (IP7500MEDIA_U15_BASE + 2) +#define IP7500MEDIA_IO3 (IP7500MEDIA_U15_BASE + 3) +#define IP7500MEDIA_IO4 (IP7500MEDIA_U15_BASE + 4) +#define IP7500MEDIA_IO5 (IP7500MEDIA_U15_BASE + 5) +#define IP7500MEDIA_IO6 (IP7500MEDIA_U15_BASE + 6) +#define IP7500MEDIA_IO7 (IP7500MEDIA_U15_BASE + 7) + +/* + * U16 + */ +#define IP7500MEDIA_U16_BASE (32 * 11) +#define IP7500MEDIA_IO8 (IP7500MEDIA_U16_BASE + 0) +#define IP7500MEDIA_IO9 (IP7500MEDIA_U16_BASE + 1) +#define IP7500MEDIA_IO10 (IP7500MEDIA_U16_BASE + 2) +#define IP7500MEDIA_IO11 (IP7500MEDIA_U16_BASE + 3) +#define IP7500MEDIA_IO12 (IP7500MEDIA_U16_BASE + 4) +#define IP7500MEDIA_IO13 (IP7500MEDIA_U16_BASE + 5) +#define IP7500MEDIA_IO14 (IP7500MEDIA_U16_BASE + 6) +#define IP7500MEDIA_IO15 (IP7500MEDIA_U16_BASE + 7) + +/* + * U17 + */ +#define IP7500MEDIA_U17_BASE (32 * 12) +#define IP7500MEDIA_IO16 (IP7500MEDIA_U17_BASE + 0) +#define IP7500MEDIA_IO17 (IP7500MEDIA_U17_BASE + 1) +#define IP7500MEDIA_IO18 (IP7500MEDIA_U17_BASE + 2) +#define IP7500MEDIA_IO19 (IP7500MEDIA_U17_BASE + 3) +#define IP7500MEDIA_IO20 (IP7500MEDIA_U17_BASE + 4) +#define IP7500MEDIA_IO21 (IP7500MEDIA_U17_BASE + 5) +#define IP7500MEDIA_IO22 (IP7500MEDIA_U17_BASE + 6) +#define IP7500MEDIA_IO23 (IP7500MEDIA_U17_BASE + 7) + +/* + * U18 + */ +#define IP7500MEDIA_U18_BASE (32 * 13) +#define IP7500MEDIA_IO24 (IP7500MEDIA_U18_BASE + 0) +#define IP7500MEDIA_IO25 (IP7500MEDIA_U18_BASE + 1) +#define IP7500MEDIA_IO26 (IP7500MEDIA_U18_BASE + 2) +#define IP7500MEDIA_IO27 (IP7500MEDIA_U18_BASE + 3) +#define IP7500MEDIA_IO28 (IP7500MEDIA_U18_BASE + 4) +#define IP7500MEDIA_IO29 (IP7500MEDIA_U18_BASE + 5) +#define IP7500MEDIA_IO30 (IP7500MEDIA_U18_BASE + 6) +#define IP7500MEDIA_IO31 (IP7500MEDIA_U18_BASE + 7) +#endif + +#ifdef CONFIG_IP7145DPF +/* + * U48 + */ +#define IP7145DPF_U48_BASE (32 * 10) +#define IP7145DPF_IO0 (IP7145DPF_U48_BASE + 0) +#define IP7145DPF_IO1 (IP7145DPF_U48_BASE + 1) +#define IP7145DPF_IO2 (IP7145DPF_U48_BASE + 2) +#define IP7145DPF_IO3 (IP7145DPF_U48_BASE + 3) +#define IP7145DPF_IO4 (IP7145DPF_U48_BASE + 4) +#define IP7145DPF_IO5 (IP7145DPF_U48_BASE + 5) +#define IP7145DPF_IO6 (IP7145DPF_U48_BASE + 6) +#define IP7145DPF_IO7 (IP7145DPF_U48_BASE + 7) + +/* + * U72 + */ +#define IP7145DPF_U72_BASE (32 * 11) +#define IP7145DPF_IOB0 (IP7145DPF_U72_BASE + 0) +#define IP7145DPF_IOB1 (IP7145DPF_U72_BASE + 1) +#define IP7145DPF_IOB2 (IP7145DPF_U72_BASE + 2) +#define IP7145DPF_IOB3 (IP7145DPF_U72_BASE + 3) +#define IP7145DPF_IOB4 (IP7145DPF_U72_BASE + 4) +#define IP7145DPF_IOB5 (IP7145DPF_U72_BASE + 5) +#define IP7145DPF_IOB6 (IP7145DPF_U72_BASE + 6) +#define IP7145DPF_IOB7 (IP7145DPF_U72_BASE + 7) +#endif + +#include + +/* + * The following macros bypass gpiolib to generate direct references + * to the port registers. These assume, minimally, that either + * gpio_direction_input() or gpio_direction_output() have already been + * called to setup the pin direction and to enable the pin function to + * be gpio. These macros generate the hardware port address based on + * the assumption that all ports are 32 bits wide (even though we know + * they are not). This is so we can efficiently turn pin numbers into + * port addresses without a lookup. + * + * These operations must be done in one instruction to prevent clobbering + * other thread's accesses to the same port. + */ +#define UBICOM32_GPIO_ENABLE(pin) \ + do { \ + asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t" \ + : \ + : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_mask), \ + [mask] "d" (gpio_bit(pin)) \ + : "cc", "memory" \ + ); \ + } while (0); + +#define UBICOM32_GPIO_DISABLE(pin) \ + do { \ + asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t" \ + : \ + : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_mask), \ + [mask] "d" (~gpio_bit(pin)) \ + : "cc", "memory" \ + ); \ + } while (0); + +#define UBICOM32_GPIO_SET_PIN_INPUT(pin) \ + do { \ + asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t" \ + : \ + : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_ctl), \ + [mask] "d" (~gpio_bit(pin)) \ + : "cc", "memory" \ + ); \ + } while (0); + +#define UBICOM32_GPIO_SET_PIN_OUTPUT(pin) \ + do { \ + asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t" \ + : \ + : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_ctl), \ + [mask] "d" (gpio_bit(pin)) \ + : "cc", "memory" \ + ); \ + } while (0); + +#define UBICOM32_GPIO_SET_PIN_TOGGLE(pin) \ + do { \ + asm volatile ("xor.4 (%[port]), (%[port]), %[mask]\n\t" \ + : \ + : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out), \ + [mask] "d" (gpio_bit(pin)) \ + : "cc", "memory" \ + ); \ + } while (0); + +#define UBICOM32_GPIO_SET_PIN_HIGH(pin) \ + do { \ + asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t" \ + : \ + : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out), \ + [mask] "d" (gpio_bit(pin)) \ + : "cc", "memory" \ + ); \ + } while (0); + +#define UBICOM32_GPIO_SET_PIN_LOW(pin) \ + do { \ + asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t" \ + : \ + : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out), \ + [mask] "d" (~gpio_bit(pin)) \ + : "cc", "memory" \ + ); \ + } while (0); + +#define UBICOM32_GPIO_SET_PIN(pin, val) \ + if ( val ) { \ + UBICOM32_GPIO_SET_PIN_HIGH(pin); \ + } else { \ + UBICOM32_GPIO_SET_PIN_LOW(pin); \ + } + +#define UBICOM32_GPIO_GET_PIN(pin) \ + (0 != (UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_in \ + & gpio_bit(pin))) + + +static inline int gpio_get_value(unsigned gpio) +{ + if (gpio <= MAX_UBICOM_ONCHIP_GPIO) + return UBICOM32_GPIO_GET_PIN(gpio); + else + return __gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + if (gpio <= MAX_UBICOM_ONCHIP_GPIO) + { + UBICOM32_GPIO_SET_PIN(gpio, value); + } + else + { + __gpio_set_value(gpio, value); + } +} + +static inline int gpio_cansleep(unsigned gpio) +{ + return __gpio_cansleep(gpio); +} + +static inline int gpio_to_irq(unsigned gpio) +{ +#if defined(IP5000) || defined(IP5000_REV2) + if ((gpio >= GPIO_RA_4) && (gpio <= GPIO_RA_6)) + return 25; + else + return -ENXIO; + +#elif defined(IP7000) || defined(IP7000_REV2) + if ((gpio >= GPIO_RA_4) && (gpio <= GPIO_RA_6)) + return 44 + (gpio - GPIO_RA_4); + else + return -ENXIO; + +#else + return -ENXIO; + +#endif +} + +static inline int irq_to_gpio(unsigned gpio) +{ + return -ENXIO; +} + +extern struct ubicom32_io_port *ubi_gpio_get_port(unsigned gpio); + +extern int __init ubi_gpio_init(void); + +#endif /* _ASM_UBICOM32_GPIO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/hardirq.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/hardirq.h new file mode 100644 index 000000000..e230481a1 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/hardirq.h @@ -0,0 +1,55 @@ +/* + * arch/ubicom32/include/asm/hardirq.h + * Definition of ack_bad_irq() for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1997, 98, 99, 2000, 01, 05 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2001 MIPS Technologies, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_HARDIRQ_H +#define _ASM_UBICOM32_HARDIRQ_H + +#include +#include + +/* + * The hardirq mask has to be large enough to have space + * for potentially all IRQ sources in the system nesting + * on a single CPU. For Ubicom32, we have 64 IRQ sources. + */ +#define HARDIRQ_BITS 6 +#if (1 << HARDIRQ_BITS) < NR_IRQS +# error HARDIRQ_BITS is too low! +#endif + +typedef struct { + unsigned int __softirq_pending; +} ____cacheline_aligned irq_cpustat_t; + +#include /* Standard mappings for irq_cpustat_t above */ + +extern void ack_bad_irq(unsigned int irq); + +#endif /* _ASM_UBICOM32_HARDIRQ_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/hw_irq.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/hw_irq.h new file mode 100644 index 000000000..9dece3108 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/hw_irq.h @@ -0,0 +1,31 @@ +/* + * arch/ubicom32/include/asm/hw_irq.h + * Ubicom32 architecture APIC support. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_HW_IRQ_H +#define _ASM_UBICOM32_HW_IRQ_H + +#endif /* _ASM_UBICOM32_HW_IRQ_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/io.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/io.h new file mode 100644 index 000000000..ad526a338 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/io.h @@ -0,0 +1,313 @@ +/* + * arch/ubicom32/include/asm/io.h + * I/O memory accessor functions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_IO_H +#define _ASM_UBICOM32_IO_H + +#ifdef __KERNEL__ +#include +#include + +static inline unsigned short _swapw(volatile unsigned short v) +{ + return ((v << 8) | (v >> 8)); +} + +static inline unsigned int _swapl(volatile unsigned long v) +{ + return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24)); +} + +#ifndef CONFIG_PCI +#define readb(addr) \ + ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; }) +#define readw(addr) \ + ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; }) +#define readl(addr) \ + ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; }) + +#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b)) +#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b)) +#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b)) +#else /*CONFIG_PCI */ + +#define PCI_CPU_REG_BASE (0x00000000UL) /* taking lower 2GB space */ +#define PCI_DEV_REG_BASE (0x80000000UL) + +#if PCI_CPU_REG_BASE > PCI_DEV_REG_BASE +#define IS_PCI_ADDRESS(x) (((unsigned int)(x)&(PCI_CPU_REG_BASE)) == 0) +#else +#define IS_PCI_ADDRESS(x) ((unsigned int)(x)&(PCI_DEV_REG_BASE)) +#endif + +extern unsigned int ubi32_pci_read_u32(const volatile void __iomem *addr); +extern unsigned short ubi32_pci_read_u16(const volatile void __iomem *addr); +extern unsigned char ubi32_pci_read_u8(const volatile void __iomem *addr); +extern void ubi32_pci_write_u32(unsigned int val, const volatile void __iomem *addr); +extern void ubi32_pci_write_u16(unsigned short val, const volatile void __iomem *addr); +extern void ubi32_pci_write_u8(unsigned char val, const volatile void __iomem *addr); + +static inline unsigned char readb(const volatile void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + return ubi32_pci_read_u8(addr); + else + return (unsigned char)(*(volatile unsigned char *)addr); +} +static inline unsigned short readw(const volatile void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + return ubi32_pci_read_u16(addr); + else + return (unsigned short)(*(volatile unsigned short *)addr); +} + +static inline unsigned int readl(const volatile void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + return ubi32_pci_read_u32(addr); + else + return (unsigned int)(*(volatile unsigned int *)addr); +} + +static inline void writel(unsigned int val, volatile void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + ubi32_pci_write_u32(val, addr); + else + *(volatile unsigned int *)addr = val; +} + +static inline void writew(unsigned short val, volatile void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + ubi32_pci_write_u16(val, addr); + else + *(volatile unsigned short *)addr = val; +} + +static inline void writeb(unsigned char val, volatile void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + ubi32_pci_write_u8(val, addr); + else + *(volatile unsigned char *)addr = val; +} +#endif + +#define readb_relaxed(addr) readb(addr) +#define readw_relaxed(addr) readw(addr) +#define readl_relaxed(addr) readl(addr) + + +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel + +static inline void io_outsb(unsigned int addr, const void *buf, int len) +{ + volatile unsigned char *ap = (volatile unsigned char *) addr; + unsigned char *bp = (unsigned char *) buf; + while (len--) + *ap = *bp++; +} + +static inline void io_outsw(unsigned int addr, const void *buf, int len) +{ + volatile unsigned short *ap = (volatile unsigned short *) addr; + unsigned short *bp = (unsigned short *) buf; + while (len--) + *ap = _swapw(*bp++); +} + +static inline void io_outsl(unsigned int addr, const void *buf, int len) +{ + volatile unsigned int *ap = (volatile unsigned int *) addr; + unsigned int *bp = (unsigned int *) buf; + while (len--) + *ap = _swapl(*bp++); +} + +static inline void io_insb(unsigned int addr, void *buf, int len) +{ + volatile unsigned char *ap = (volatile unsigned char *) addr; + unsigned char *bp = (unsigned char *) buf; + while (len--) + *bp++ = *ap; +} + +static inline void io_insw(unsigned int addr, void *buf, int len) +{ + volatile unsigned short *ap = (volatile unsigned short *) addr; + unsigned short *bp = (unsigned short *) buf; + while (len--) + *bp++ = _swapw(*ap); +} + +static inline void io_insl(unsigned int addr, void *buf, int len) +{ + volatile unsigned int *ap = (volatile unsigned int *) addr; + unsigned int *bp = (unsigned int *) buf; + while (len--) + *bp++ = _swapl(*ap); +} + +#define mmiowb() + +/* + * make the short names macros so specific devices + * can override them as required + */ +#ifndef CONFIG_PCI +#define memset_io(a,b,c) memset((void *)(a),(b),(c)) +#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) +#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) +#else +extern void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len); +extern void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len); +extern void memset_io(volatile void __iomem *addr, int val, size_t count); +#endif + +#define inb(addr) readb(addr) +#define inw(addr) readw(addr) +#define inl(addr) readl(addr) +#define outb(x,addr) ((void) writeb(x,addr)) +#define outw(x,addr) ((void) writew(x,addr)) +#define outl(x,addr) ((void) writel(x,addr)) + +#define inb_p(addr) inb(addr) +#define inw_p(addr) inw(addr) +#define inl_p(addr) inl(addr) +#define outb_p(x,addr) outb(x,addr) +#define outw_p(x,addr) outw(x,addr) +#define outl_p(x,addr) outl(x,addr) + +#define outsb(a,b,l) io_outsb(a,b,l) +#define outsw(a,b,l) io_outsw(a,b,l) +#define outsl(a,b,l) io_outsl(a,b,l) + +#define insb(a,b,l) io_insb(a,b,l) +#define insw(a,b,l) io_insw(a,b,l) +#define insl(a,b,l) io_insl(a,b,l) + +#ifndef CONFIG_PCI +#define ioread8_rep(a,d,c) insb(a,d,c) +#define ioread16_rep(a,d,c) insw(a,d,c) +#define ioread32_rep(a,d,c) insl(a,d,c) +#define iowrite8_rep(a,s,c) outsb(a,s,c) +#define iowrite16_rep(a,s,c) outsw(a,s,c) +#define iowrite32_rep(a,s,c) outsl(a,s,c) +#else +extern void ioread8_rep(void __iomem *port, void *buf, unsigned long count); +extern void ioread16_rep(void __iomem *port, void *buf, unsigned long count); +extern void ioread32_rep(void __iomem *port, void *buf, unsigned long count); +extern void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count); +extern void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count); +extern void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count); +#endif + + +#ifndef CONFIG_PCI +#define ioread8(X) readb(X) +#define ioread16(X) readw(X) +#define ioread32(X) readl(X) +#define iowrite8(val,X) writeb(val,X) +#define iowrite16(val,X) writew(val,X) +#define iowrite32(val,X) writel(val,X) +#else /*CONFIG_PCI */ +extern unsigned char ioread8(void __iomem *addr); +extern unsigned short ioread16(void __iomem *addr); +extern unsigned int ioread32(void __iomem *addr); +extern void iowrite8(unsigned char val, void __iomem *addr); +extern void iowrite16(unsigned short val, void __iomem *addr); +extern void iowrite32(unsigned int val, void __iomem *addr); +#endif /* CONFIG_PCI */ + +#define IO_SPACE_LIMIT 0xffff + +/* Values for nocacheflag and cmode */ +#define IOMAP_FULL_CACHING 0 +#define IOMAP_NOCACHE_SER 1 +#define IOMAP_NOCACHE_NONSER 2 +#define IOMAP_WRITETHROUGH 3 + +extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag); +extern void __iounmap(void *addr, unsigned long size); + +static inline void *ioremap(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); +} +static inline void *ioremap_nocache(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); +} +static inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); +} +static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_FULL_CACHING); +} + +extern void iounmap(void *addr); + +#define ioport_map(port, nr) ((void __iomem*)(port)) +#define ioport_unmap(addr) + + +/* Pages to physical address... */ +#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) +#define page_to_bus(page) ((page - mem_map) << PAGE_SHIFT) + +/* + * Macros used for converting between virtual and physical mappings. + */ +#define phys_to_virt(vaddr) ((void *) (vaddr)) +#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) + +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt + +/* + * Convert a physical pointer to a virtual kernel pointer for /dev/mem + * access + */ +#define xlate_dev_mem_ptr(p) __va(p) + +/* + * Convert a virtual cached pointer to an uncached pointer + */ +#define xlate_dev_kmem_ptr(p) p + +#endif /* __KERNEL__ */ + +#endif /* _ASM_UBICOM32_IO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctl.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctl.h new file mode 100644 index 000000000..10d8dd75f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctl.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/ioctl.h + * Generic ioctl.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_IOCTL_H +#define _ASM_UBICOM32_IOCTL_H + +#include + +#endif /* _ASM_UBICOM32_IOCTL_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctls.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctls.h new file mode 100644 index 000000000..c8e2c7901 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctls.h @@ -0,0 +1,111 @@ +/* + * arch/ubicom32/include/asm/ioctls.h + * Definitions of ioctls for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_IOCTLS_H +#define _ASM_UBICOM32_IOCTLS_H + +#include + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TIOCSBRK 0x5427 /* BSD compatibility */ +#define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TCGETS2 _IOR('T',0x2A, struct termios2) +#define TCSETS2 _IOW('T',0x2B, struct termios2) +#define TCSETSW2 _IOW('T',0x2C, struct termios2) +#define TCSETSF2 _IOW('T',0x2D, struct termios2) +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define FIOQSIZE 0x545E + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +#endif /* _ASM_UBICOM32_IOCTLS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000-asm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000-asm.h new file mode 100644 index 000000000..62929e49f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000-asm.h @@ -0,0 +1,156 @@ +/* + * arch/ubicom32/include/asm/ip5000-asm.h + * Instruction macros for the IP5000. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_IP5000_ASM_H +#define _ASM_UBICOM32_IP5000_ASM_H + +#if !defined(__LINKER__) + +#if defined(__ASSEMBLY__) +.macro cycles quant +.if (\quant) == 1 + nop +.else +.if (((\quant) + 3) / 8) > 0 +.rept (((\quant) + 3) / 8) + jmpt.f .+4 +.endr +.endif +.if ((((\quant) + 3) % 8) / 4) > 0 + jmpt.t .+4 +.endif +.endif +.endm +#else +/* + * Same macro as above just in C inline asm + */ +asm (" \n\ +.macro cycles quant \n\ +.if (\\quant) == 1 \n\ + nop \n\ +.else \n\ +.if (((\\quant) + 3) / 8) > 0 \n\ +.rept (((\\quant) + 3) / 8) \n\ + jmpt.f .+4 \n\ +.endr \n\ +.endif \n\ +.if ((((\\quant) + 3) % 8) / 4) > 0 \n\ + jmpt.t .+4 \n\ +.endif \n\ +.endif \n\ +.endm \n\ +"); +#endif + + +#if defined(__ASSEMBLY__) +.macro pipe_flush cyc + cycles 11 - (\cyc) +.endm +#else +/* + * Same macro as above just in C inline asm + */ +asm (" \n\ +.macro pipe_flush cyc \n\ + cycles 11 - (\\cyc) \n\ +.endm \n\ +"); + +#endif + +#if defined(__ASSEMBLY__) +.macro setcsr_flush cyc + cycles 5 - (\cyc) +.endm +#else +/* + * Same macro as above just in C inline asm + */ +asm (" \n\ +.macro setcsr_flush cyc \n\ + cycles 5 - (\\cyc) \n\ +.endm \n\ +"); +#endif + +/* + * Macros for prefetch (using miss-aligned memory write) + */ +#if defined(__ASSEMBLY__) + +.macro pre_fetch_macro thread_num, Ascratch, Aaddress length + bclr MT_TRAP_EN, MT_TRAP_EN, #(\thread_num) + bset \Ascratch, \Aaddress, #0 ; force a miss-aligned address + jmpt.t .+4 ; delay for both address setup and trap disable + move.4 (\Ascratch), #0 + .if (\length > 32) + move.4 32(\Ascratch), #0 + .endif + .if (\length > 64) + move.4 64(\Ascratch), #0 + .endif + .if (\length > 96) + move.4 96(\Ascratch), #0 + .endif + .if (\length > 128) + invalid_instruction ; maximum pre-fetch size is 4 cache lines + .endif + bset MT_TRAP_EN, MT_TRAP_EN, #(\thread_num) +.endm + +#else +/* + * Same macro as above just in C inline asm + */ +asm (" \n\ +.macro pre_fetch_macro thread_num, Ascratch, Aaddress length \n\ + bclr MT_TRAP_EN, MT_TRAP_EN, #(\thread_num) \n\ + bset \\Ascratch, \\Aaddress, #0 ; force a miss-aligned address \n\ + jmpt.t .+4 ; delay for both address setup and trap disable \n\ + move.4 (\\Ascratch), #0 \n\ + .if (\\length > 32) \n\ + move.4 32(\\Ascratch), #0 \n\ + .endif \n\ + .if (\\length > 64) \n\ + move.4 64(\\Ascratch), #0 \n\ + .endif \n\ + .if (\\length > 96) \n\ + move.4 96(\\Ascratch), #0 \n\ + .endif \n\ + .if (\\length > 128) \n\ + invalid_instruction ; maximum pre-fetch size is 4 cache lines \n\ + .endif \n\ + bset MT_TRAP_EN, MT_TRAP_EN, #(\\thread_num) \n\ +.endm \n\ +"); +#endif + +#endif /* !defined(__LINKER__) */ +#endif /* defined _ASM_UBICOM32_IP5000_ASM_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000.h new file mode 100644 index 000000000..b616ebe5f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000.h @@ -0,0 +1,845 @@ +/* + * arch/ubicom32/include/asm/ip5000.h + * Specific details for the Ubicom IP5000 processor. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_IP5000_H +#define _ASM_UBICOM32_IP5000_H + +#include + +/* + * Inline assembly define + */ +#define S(arg) #arg +#define D(arg) S(arg) + +/* + * Assembler include file + */ +#include + +/* + * Timing + */ +#define JMPT_PENALTY 3 +#define JMPF_PENALTY 7 +#define RET_PENALTY 7 + +/* + * Threads + */ +#if defined(IP5000) || defined(IP5000_REV2) +#define THREAD_COUNT 10 +#elif defined(IP7000) || defined(IP7000_REV2) +#define THREAD_COUNT 12 +#else +#error "Unknown IP5K silicon" +#endif + +/* + * Arch + */ +#if defined(IP5000) || defined(IP5000_REV2) +#define UBICOM32_ARCH_VERSION 3 +#elif defined(IP7000) || defined(IP7000_REV2) +#define UBICOM32_ARCH_VERSION 4 +#else +#error "Unknown IP5K silicon" +#endif + + +/* + * Registers + */ +#define ROSR_INT (1 << 0) + +/* Interrupts */ +#define INT_CHIP(reg, bit) (((reg) << 5) | (bit)) +#define INT_REG(interrupt) (((interrupt) >> 5) * 4) +#define INT_SET(interrupt) 0x0114 + INT_REG(interrupt) +#define INT_CLR(interrupt) 0x0124 + INT_REG(interrupt) +#define INT_STAT(interrupt) 0x0104 + INT_REG(interrupt) +#define INT_MASK(interrupt) 0x00C0 + INT_REG(interrupt) +#define INT_BIT(interrupt) ((interrupt) & 0x1F) +#define INT_BIT_MASK(interrupt) (1 << INT_BIT(interrupt)) + +/* + * The LOCK_INT and THREAD_INT are used to wake up corresponding thread. They are sharing + * the same set of SW interrupt resource. + * + * LOCK_INT(n): One SW INT per NRT thread that can participate lock operation. + * The threads that can participate lock are application threads and DSR thread. + * (Lock locks - numbers are hard-coded in lock.h) + * THREAD_INT(n): One SW INT per HRT thread for wake up trigger. + */ +#define LOCK_INT(thread) INT_CHIP(0, (thread)) +#define THREAD_INT(thread) INT_CHIP(0, (thread)) + +/* + * The SYSTEM_INT and DSR_INT are sharing the same set of SW interrupt resource. + * + * SYSTEM_INT(n): One SW INT per NRT threads (application threads) as system queue interrupt, + * and for DSR as self-trigger interrupt. + * (The application threads include at least thread 0) + * DSR_INT(n): One SW INT per HRT thread to request DSR service. + */ +#define SYSTEM_INT(thread) INT_CHIP(0, THREAD_COUNT + (thread)) +#define DSR_INT(thread) INT_CHIP(0, THREAD_COUNT + (thread)) + +/* GLOBAL_CTRL */ +#define GLOBAL_CTRL_TRAP_RST_EN (1 << 9) +#define GLOBAL_CTRL_AERROR_RST_EN (1 << 8) +#define GLOBAL_CTRL_MT_MIN_DELAY(x) ((x) << 3) +#define GLOBAL_CTRL_HRT_BANK_SELECT (1 << 2) +#define GLOBAL_CTRL_INT_EN (1 << 0) + +/* + * HRT Tables + */ +#define HRT_TABLE0_BASE 0x0800 +#define HRT_TABLE1_BASE 0x0900 +#define HRT_TABLE_SIZE 64 + +/* + * Break Point Trap Register + */ +#define ASYNCERROR_INT INT_CHIP(0, 31) +#define BREAKPOINT_INT INT_CHIP(1, 31) + +/* + * Port interrupts + * The non-existing FIFO INTs are mapped to INT2 for the ports. + */ +#define IO_PORT_PTR_TO_NUM(port) (((port) & 0x0000ffff) >> 12) +#define RX_FIFO_INT(port) \ + ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 25) : \ + ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 26) : \ + ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \ + ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 24) : \ + ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 27) : \ + ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 16) : \ + ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \ + ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \ + ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 21) : \ + INT_CHIP(1, 15)))))))))) +#define TX_FIFO_INT(port) \ + ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 24) : \ + ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 27) : \ + ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \ + ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 25) : \ + ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 28) : \ + ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 17) : \ + ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \ + ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \ + ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 22) : \ + INT_CHIP(1, 15)))))))))) +#define PORT_OTHER_INT(port) \ + ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 25) : \ + ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 28) : \ + ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \ + ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 26) : \ + ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 29) : \ + ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 18) : \ + ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \ + ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \ + ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 23) : \ + INT_CHIP(1, 15)))))))))) + +/* + * On Chip Peripherals Base. + */ +#define OCP_BASE 0x01000000 +#define OCP_GENERAL 0x000 +#define OCP_TIMERS 0x100 +#define OCP_TRNG 0x200 /* True Random Number Generator Control Reigsters */ +#define OCP_DEBUG 0x300 +#define OCP_SECURITY 0x400 +#define OCP_ICCR 0x500 /* I-Cache Control Registers */ +#define OCP_DCCR 0x600 /* D-Cache Control Registers */ +#define OCP_OCMC 0x700 /* On Chip Memory Control Registers */ +#define OCP_STATISTICS 0x800 /* Statistics Counters */ +#define OCP_MTEST 0x900 /* Memory Test Registers */ +#define OCP_MCFG 0xa00 /* Memory Configuration Registers -- IP7000 only */ +#define OCP_DEBUG_INST 0x000 /* Up to 16M */ + +/* + * General Configuration Registers (PLL) + */ +#define GENERAL_CFG_BASE (OCP_BASE + OCP_GENERAL) +#define GEN_CLK_CORE_CFG 0x00 +#define GEN_CLK_IO_CFG 0x04 +#define GEN_CLK_DDR_CFG 0x08 +#define GEN_CLK_DDRDS_CFG 0x0c +#define GEN_CLK_SLIP_CLR 0x10 +#define GEN_CLK_SLIP_START 0x14 +#define GEN_CLK_SERDES_SEL 0x18 /* IP7000 only */ +#define GEN_CLK_DDR_CFG2 0x1c /* IP7000 only */ +#define GEN_DDR_CAL_CTRL 0x30 /* IP5000 only */ +#define GEN_DDR_CAL_STAT 0x34 /* IP5000 only */ +#define GEN_USB_DFT_CTRL 0x38 /* IP5000 only */ +#define GEN_USB_DFT_STAT 0x3c /* IP5000 only */ +#define GEN_USB_PHY_CFG 0x40 /* IP7000 only */ +#define GEN_USB_PHY_TEST 0x44 /* IP7000 only */ +#define GEN_USB_PHY_STAT 0x48 /* IP7000 only */ +#define GEN_SW_RESET 0x80 +#define GEN_RESET_REASON 0x84 +#define GEN_BOND_CFG 0x88 +#define GEN_IO_PU_CFG 0x8c +#define GEN_MEM_RM_CFG 0x90 +#define GEN_IO_CONFIG 0x94 + +#define GEN_CLK_PLL_SECURITY_BIT_NO 31 +#define GEN_CLK_PLL_SECURITY (1 << GEN_CLK_PLL_SECURITY_BIT_NO) +#define GEN_CLK_PLL_ENSAT (1 << 30) +#define GEN_CLK_PLL_FASTEN (1 << 29) +#define GEN_CLK_PLL_NR(v) (((v) - 1) << 23) +#define GEN_CLK_PLL_NF(v) (((v) - 1) << 11) +#define GEN_CLK_PLL_OD(v) (((v) - 1) << 8) +#define GEN_CLK_PLL_RESET (1 << 7) +#define GEN_CLK_PLL_BYPASS (1 << 6) +#define GEN_CLK_PLL_POWERDOWN (1 << 5) +#define GEN_CLK_PLL_SELECT (1 << 4) + +#define GEN_GET_CLK_PLL_NR(v) ((((v) >> 23) & 0x003f) + 1) +#define GEN_GET_CLK_PLL_NF(v) ((((v) >> 11) & 0x0fff) + 1) +#define GEN_GET_CLK_PLL_OD(v) ((((v) >> 8) & 0x7) + 1) + + +#define RESET_FLAG_DST_MEM_ERROR (1 << 18) +#define RESET_FLAG_SRC1_MEM_ERROR (1 << 17) +#define RESET_FLAG_WRITE_ADDR (1 << 16) +#define RESET_FLAG_DST_SYNC_ERROR (1 << 15) +#define RESET_FLAG_SRC1_SYNC_ERROR (1 << 14) +#define RESET_FLAG_DST_ALGN_ERROR (1 << 13) +#define RESET_FLAG_SRC1_ALGN_ERROR (1 << 12) +#define RESET_FLAG_DST_ADDR_ERROR (1 << 11) +#define RESET_FLAG_SRC1_ADDR_ERROR (1 << 10) +#define RESET_FLAG_ILLEGAL_INST (1 << 9) +#define RESET_FLAG_INST_SYNC_ERROR (1 << 8) +#define RESET_FLAG_INST_ADDR_ERROR (1 << 7) +#define RESET_FLAG_DATA_PORT_ERROR (1 << 6) +#define RESET_FLAG_INST_PORT_ERROR (1 << 5) +#define RESET_FLAG_SW_RESET (1 << 4) +#define RESET_FLAG_DEBUG (1 << 3) +#define RESET_FLAG_WATCHDOG (1 << 2) +#define RESET_FLAG_POWER_ON (1 << 1) +#define RESET_FLAG_EXTERNAL (1 << 0) + +/* + * Timer block + */ +#define TIMER_BASE (OCP_BASE + OCP_TIMERS) +#define TIMER_MPTVAL 0x00 +#define TIMER_RTCOM 0x04 +#define TIMER_TKEY 0x08 +#define TIMER_WDCOM 0x0c +#define TIMER_WDCFG 0x10 +#define TIMER_SYSVAL 0x14 +#define TIMER_SYSCOM(tmr) (0x18 + (tmr) * 4) +#define TIMER_TRN_CFG 0x100 +#define TIMER_TRN 0x104 + +#define TIMER_COUNT 10 +#define TIMER_INT(tmr) INT_CHIP(1, (tmr)) +#define TIMER_TKEYVAL 0xa1b2c3d4 +#define TIMER_WATCHDOG_DISABLE 0x4d3c2b1a +#define TIMER_TRN_CFG_ENABLE_OSC 0x00000007 + +#ifndef __ASSEMBLY__ +/* + * ubicom32_io_timer + */ +struct ubicom32_io_timer { + volatile u32_t mptval; + volatile u32_t rtcom; + volatile u32_t tkey; + volatile u32_t wdcom; + volatile u32_t wdcfg; + volatile u32_t sysval; + volatile u32_t syscom[TIMER_COUNT]; + volatile u32_t reserved[64 - 6 - TIMER_COUNT]; // skip all the way to OCP-TRNG section + volatile u32_t rsgcfg; + volatile u32_t trn; +}; + +#define UBICOM32_IO_TIMER ((struct ubicom32_io_timer *)TIMER_BASE) +#endif + +#define UBICOM32_VECTOR_TO_TIMER_INDEX(vector) (vector - TIMER_INT(0)) + +/* + * OCP-Debug Module (Mailbox) + */ +#define ISD_MAILBOX_BASE (OCP_BASE + OCP_DEBUG) +#define ISD_MAILBOX_IN 0x00 +#define ISD_MAILBOX_OUT 0x04 +#define ISD_MAILBOX_STATUS 0x08 + +#define ISD_MAILBOX_INT INT_CHIP(1, 30) + +#define ISD_MAILBOX_STATUS_IN_FULL (1 << 31) +#define ISD_MAILBOX_STATUS_IN_EMPTY (1 << 30) +#define ISD_MAILBOX_STATUS_OUT_FULL (1 << 29) +#define ISD_MAILBOX_STATUS_OUT_EMPTY (1 << 28) + +/* + * OCP-Security + */ +#define SECURITY_BASE (OCP_BASE + OCP_SECURITY) +#define SECURITY_BASE_EFFECTIVE_ADDRESS (SECURITY_BASE >> 7) // To load the base address in a single instruction +#define SECURITY_CTRL 0x00 +#define SECURITY_CTRL_BYTE_OFFSET(x) ((x) << 16) +#define SECURITY_CTRL_KEY_SIZE(x) ((x) << 8) +#define SECURITY_CTRL_HASH_ALG_NONE (0 << 4) +#define SECURITY_CTRL_HASH_ALG_MD5 (1 << 4) +#define SECURITY_CTRL_HASH_ALG_SHA1 (2 << 4) +#define SECURITY_CTRL_CBC (1 << 3) +#define SECURITY_CTRL_CIPHER_ALG_AES (0 << 1) +#define SECURITY_CTRL_CIPHER_ALG_NONE (1 << 1) +#define SECURITY_CTRL_CIPHER_ALG_DES (2 << 1) +#define SECURITY_CTRL_CIPHER_ALG_3DES (3 << 1) +#define SECURITY_CTRL_ENCIPHER (1 << 0) +#define SECURITY_CTRL_DECIPHER (0 << 0) +#define SECURITY_STAT 0x04 +#define SECURITY_STAT_BUSY (1 << 0) +#define SECURITY_KEY_VALUE(x) (0x10 + (x) * 4) +#define SECURITY_KEY_IN(x) (0x30 + (x) * 4) +#define SECURITY_KEY_OUT(x) (0x50 + (x) * 4) +#define SECURITY_KEY_HASH(x) (0x70 + (x) * 4) + +/* + * OCP-ICCR + */ +#define ICCR_BASE (OCP_BASE + OCP_ICCR) +#define ICACHE_TOTAL_SIZE 16384 /* in bytes */ + +/* + * OCP-DCCR + */ +#define DCCR_BASE (OCP_BASE + OCP_DCCR) +#if defined(IP5000) || defined(IP5000_REV2) +#define DCACHE_TOTAL_SIZE 8192 /* in bytes */ +#elif defined(IP7000) || defined(IP7000_REV2) +#define DCACHE_TOTAL_SIZE 16384 /* in bytes */ +#endif + +#if defined(IP5000) || defined(IP5000_REV2) || defined(IP7000) || defined(IP7000_REV2) +#define DCACHE_WRITE_QUEUE_LENGTH 6 +#else +#error "Unknown IP5K silicon" +#endif + +#define CACHE_LINE_SIZE 32 /* in bytes */ + +#define CCR_ADDR 0x00 +#define CCR_RDD 0x04 +#define CCR_WRD 0x08 +#define CCR_STAT 0x0c +#define CCR_CTRL 0x10 + +#define CCR_STAT_MCBE 0 +#define CCR_STAT_WIDEL 1 /* D-cache only */ + +#define CCR_CTRL_DONE 0 +#define CCR_CTRL_RESET 2 +#define CCR_CTRL_VALID 3 +#define CCR_CTRL_RD_DATA (1 << 4) +#define CCR_CTRL_RD_TAG (2 << 4) +#define CCR_CTRL_WR_DATA (3 << 4) +#define CCR_CTRL_WR_TAG (4 << 4) +#define CCR_CTRL_INV_INDEX (5 << 4) +#define CCR_CTRL_INV_ADDR (6 << 4) +#define CCR_CTRL_FLUSH_INDEX (7 << 4) /* D-cache only */ +#define CCR_CTRL_FLUSH_INV_INDEX (8 << 4) /* D-cache only */ +#define CCR_CTRL_FLUSH_ADDR (9 << 4) /* D-cache only */ +#define CCR_CTRL_FLUSH_INV_ADDR (10 << 4) /* D-cache only */ + +/* + * OCP-OCMC + */ +#define OCMC_BASE (OCP_BASE + OCP_OCMC) +#define OCMC_BANK_MASK 0x00 +#define OCMC_BIST_CNTL 0x04 /* IP5000 only */ +#define OCMC_BIST_STAT 0x08 /* IP5000 only */ + +#define OCMC_BANK_PROG(n) ((1<<(n))-1) + +#define OCMC_BIST_WRCK (1 << 7) +#define OCMC_BIST_RESET (1 << 5) +#define OCMC_BIST_SMART (1 << 4) +#define OCMC_BIST_RUN (1 << 3) +#define OCMC_BIST_REPAIR (1 << 2) + +#define OCMC_BIST_READY (1 << 3) +#define OCMC_BIST_FAIL (1 << 2) + +/* + * OCP-STATISTICS + */ +#define STATISTICS_BASE (OCP_BASE + OCP_STATISTICS) +#define STAT_COUNTER_CTRL(n) ((n)*8) +#define STAT_COUNTER(n) ((n)*8 + 4) + +#define STAT_EVENT_MP_INST 0 +#define STAT_EVENT_OCM_ACCESS 4 +#define STAT_EVENT_OCM_REQ 5 +#define STAT_EVENT_IC_REQ_INVAL 13 +#define STAT_EVENT_IC_MISS_INVAL 14 +#define STAT_EVENT_IC_REQ_INVAL_NACK 15 +#define STAT_EVENT_IC_REQ_VAL 16 +#define STAT_EVENT_IC_MISS_VAL 17 +#define STAT_EVENT_IC_REQ_VAL_NACK 18 +#define STAT_EVENT_IC_MISS_Q 19 +#define STAT_EVENT_DC_RD_REQ 20 +#define STAT_EVENT_DC_RD_MISS 21 +#define STAT_EVENT_DC_WR_REQ 22 +#define STAT_EVENT_DC_WR_MISS 23 +#define STAT_EVENT_DC_MISS_Q 24 +#define STAT_EVENT_DC_WB_FULL 25 +#define STAT_EVENT_DC_REQ_NACK 26 +#define STAT_EVENT_DC_CORE_REQ 27 +#define STAT_EVENT_DC_MISS 28 +#define STAT_EVENT_DC_EVICT 29 +#define STAT_EVENT_TRUE 30 +#define STAT_EVENT_FALSE 31 + +/* + * OCP_MTEST + */ +#define MTEST_BASE (OCP_BASE + OCP_MTEST) +#define MTEST_ADDR 0x00 +#define MTEST_WR 0x04 +#define MTEST_RD 0x08 +#define MTEST_CTRL 0x0c + +/* + * OCP_MCFG (IP7000 only) + */ +#define MCFG_BASE (OCP_BASE + OCP_MCFG) +#define MCFG_CTRL 0x00 +#define MCFG_WCFG 0x04 +#define MCFG_RCFG 0x08 + +/* + * Port registers + */ +#define IO_BASE 0x02000000 +#define RA (IO_BASE + 0x00000000) +#define RB (IO_BASE + 0x00001000) +#define RC (IO_BASE + 0x00002000) +#define RD (IO_BASE + 0x00003000) +#define RE (IO_BASE + 0x00004000) +#define RF (IO_BASE + 0x00005000) +#define RG (IO_BASE + 0x00006000) +#define RH (IO_BASE + 0x00007000) +#define RI (IO_BASE + 0x00008000) +#define RJ (IO_BASE + 0x00009000) +#define RLATCH (IO_BASE + 0x00ff0000) // For latched output only +#define IO_PORT_BR_OFFSET 0x00000800 + +/* + * General I/O Register Map (per port) + */ +#define IO_FUNC 0x00 +#define IO_GPIO_CTL 0x04 +#define IO_GPIO_OUT 0x08 +#define IO_GPIO_IN 0x0C +#define IO_INT_STATUS 0x10 +#define IO_INT_MASK 0x14 +#define IO_INT_SET 0x18 +#define IO_INT_CLR 0x1C +#define IO_TX_FIFO 0x20 +#define IO_TX_FIFO_HI 0x24 +#define IO_RX_FIFO 0x28 +#define IO_RX_FIFO_HI 0x2c +#define IO_CTL0 0x30 +#define IO_CTL1 0x34 +#define IO_CTL2 0x38 +#define IO_STATUS0 0x3c +#define IO_STATUS1 0x40 +#define IO_STATUS2 0x44 +#define IO_FIFO_WATER 0x48 +#define IO_FIFO_LEVEL 0x4c +#define IO_GPIO_MASK 0x50 + +#define IO_FUNC_FUNCTION_RESET(func) ((1 << ((func) - 1)) << 4) /* Function 0 doesn't need reset */ +#define IO_FUNC_RX_FIFO (1 << 3) +#define IO_FUNC_SELECT(func) ((func) << 0) + +/* + * External interrupt pins. + */ +#define EXT_INT_IO_BIT(pin) ((pin) + 5) // Interrupt pin number -> I/O INT bit +#define EXT_INT_RISING_EDGE(pin) (0x2 << (2*(pin) + 7)) +#define EXT_INT_FALLING_EDGE(pin) (0x1 << (2*(pin) + 7)) + +/* + * Flash + */ +#define IO_XFL_BASE RA + +#define IO_XFL_INT_START (1 << 16) +#define IO_XFL_INT_ERR (1 << 8) +#define IO_XFL_INT_DONE (1 << 0) + +#define IO_XFL_CTL0_MASK (0xffe07fff) +#define IO_XFL_CTL0_RD_CMD(cmd) (((cmd) & 0xff) << 24) +#define IO_XFL_CTL0_RD_DUMMY(n) (((n) & 0x7) << 21) +#define IO_XFL_CTL0_CLK_WIDTH(core_cycles) ((((core_cycles) + 1) & 0x7e) << 8) /* must be even number */ +#define IO_XFL_CTL0_CE_WAIT(spi_cycles) (((spi_cycles) & 0x3f) << 2) +#define IO_XFL_CTL0_MCB_LOCK (1 << 1) +#define IO_XFL_CTL0_ENABLE (1 << 0) +#define IO_XFL_CTL0_FAST_VALUE(div, wait) (IO_XFL_CTL0_RD_CMD(0xb) | IO_XFL_CTL0_RD_DUMMY(1) | IO_XFL_CTL0_CLK_WIDTH(div) | IO_XFL_CTL0_CE_WAIT(wait) | IO_XFL_CTL0_ENABLE) +#define IO_XFL_CTL0_VALUE(div, wait) (IO_XFL_CTL0_RD_CMD(3) | IO_XFL_CTL0_CLK_WIDTH(div) | IO_XFL_CTL0_CE_WAIT(wait) | IO_XFL_CTL0_ENABLE) + +#define IO_XFL_CTL1_MASK (0xc0003fff) +#define IO_XFL_CTL1_FC_INST(inst) (((inst) & 0x3) << 30) +#define IO_XFL_CTL1_FC_DATA(n) (((n) & 0x3ff) << 4) +#define IO_XFL_CTL1_FC_DUMMY(n) (((n) & 0x7) << 1) +#define IO_XFL_CTL1_FC_ADDR (1 << 0) + +#define IO_XFL_CTL2_FC_CMD(cmd) (((cmd) & 0xff) << 24) +#define IO_XFL_CTL2_FC_ADDR(addr) ((addr) & 0x00ffffff) /* Only up to 24 bits */ + +#define IO_XFL_STATUS0_MCB_ACTIVE (1 << 0) +#define IO_XFL_STATUS0_IOPCS_ACTIVE (1 << 1) + +/* + * SDRAM + */ +#define IO_SDRAM_DATA_BASE RG +#define IO_SDRAM_CNTL_BASE RH + +#define IO_SDRAM_CTRL0_EN_REF (1 << 0) + +/* + * Port function code (common fucntion codes for all I/O ports) + */ +#define IO_PORTX_FUNC_GPIO 0x00 +#define IO_PORTX_FUNC_XFL 0x01 +#define IO_PORTX_FUNC_PCI 0x01 +#define IO_PORTX_FUNC_SERDES 0x01 +#define IO_PORTX_FUNC_GMII 0x01 +#define IO_PORTX_FUNC_DDR 0x01 +#define IO_PORTX_FUNC_PCIX 0x01 +#define IO_PORTX_FUNC_USB2_0 0x01 +#define IO_PORTX_FUNC_GPIO_INT_CLK 0x02 +#define IO_PORTX_FUNC_PLIO 0x02 +#define IO_PORTX_FUNC_GPIO_INT 0x03 +#define IO_PORTX_FUNC_MII 0x03 + +/* + * Port 0 + */ +#define IO_PORT0_FUNC_GPIO IO_PORTX_FUNC_GPIO +#define IO_PORT0_FUNC_XFL_INT_CLK IO_PORTX_FUNC_XFL // Default mode after reset +#define IO_PORT0_FUNC_GPIO_INT_CLK IO_PORTX_FUNC_GPIO_INT_CLK +#define IO_PORT0_FUNC_GPIO_INT IO_PORTX_FUNC_GPIO_INT + +/* + * Port 1 + */ +#define IO_PORT1_FUNC_GPIO IO_PORTX_FUNC_GPIO +#define IO_PORT1_FUNC_PCI IO_PORTX_FUNC_PCI // PCI control +#define IO_PORT1_FUNC_MII IO_PORTX_FUNC_MII // port 4 MII extension + +/* + * Port 2 + */ +#define IO_PORT2_FUNC_GPIO IO_PORTX_FUNC_GPIO +#define IO_PORT2_FUNC_PCI IO_PORTX_FUNC_PCI // PCI data I/O +#define IO_PORT2_FUNC_PLIO IO_PORTX_FUNC_PLIO // Extended LM + +/* + * Port 3 + */ +#define IO_PORT3_FUNC_GPIO IO_PORTX_FUNC_GPIO +#define IO_PORT3_FUNC_SERDES IO_PORTX_FUNC_SERDES +#define IO_PORT3_FUNC_PLIO IO_PORTX_FUNC_PLIO + +/* + * Port 4 + */ +#define IO_PORT4_FUNC_GPIO IO_PORTX_FUNC_GPIO +#define IO_PORT4_FUNC_SERDES IO_PORTX_FUNC_SERDES +#define IO_PORT4_FUNC_PLIO IO_PORTX_FUNC_PLIO // Extended LM +#define IO_PORT4_FUNC_MII IO_PORTX_FUNC_MII + +/* + * Port 5 + */ +#define IO_PORT5_FUNC_GPIO IO_PORTX_FUNC_GPIO +#define IO_PORT5_FUNC_GMII IO_PORTX_FUNC_GMII + +/* + * Port 6 + */ +#define IO_PORT6_FUNC_GPIO IO_PORTX_FUNC_GPIO +#define IO_PORT6_FUNC_DDR IO_PORTX_FUNC_DDR + +/* + * Port 7 + */ +#define IO_PORT7_FUNC_GPIO IO_PORTX_FUNC_GPIO +#define IO_PORT7_FUNC_DDR IO_PORTX_FUNC_DDR + +/* + * Port 8 + */ +#define IO_PORT8_FUNC_GPIO IO_PORTX_FUNC_GPIO +#define IO_PORT8_FUNC_PCIX IO_PORTX_FUNC_PCIX +#define IO_PORT8_FUNC_PLIO IO_PORTX_FUNC_PLIO // Extended LM +#define IO_PORT8_FUNC_MII IO_PORTX_FUNC_MII // port 4 MII extension + +/* + * Port 9 + */ +#define IO_PORT9_FUNC_USB2_0 IO_PORTX_FUNC_USB2_0 + +/* + * FIFO + */ +#define IO_PORTX_INT_FIFO_TX_RESET (1 << 31) +#define IO_PORTX_INT_FIFO_RX_RESET (1 << 30) +#define IO_PORTX_INT_FIFO_TX_UF (1 << 15) +#define IO_PORTX_INT_FIFO_TX_WM (1 << 14) +#define IO_PORTX_INT_FIFO_RX_OF (1 << 13) +#define IO_PORTX_INT_FIFO_RX_WM (1 << 12) + +#define IO_PORTX_FUNC_FIFO_TX_WM(n) ((n) << 16) +#define IO_PORTX_FUNC_FIFO_RX_WM(n) ((n) << 0) + +/* + * MII + */ +#define IO_PORTX_INT_MII_TX_ERR_SEND (1 << 18) +#define IO_PORTX_INT_MII_TX_HALT (1 << 17) +#define IO_PORTX_INT_MII_TX_START (1 << 16) +#define IO_PORTX_INT_MII_THRESHOLD (1 << 8) +#define IO_PORTX_INT_MII_RX_EOP (1 << 7) +#define IO_PORTX_INT_MII_RX_SFD (1 << 6) +#define IO_PORTX_INT_MII_RX_ERR (1 << 5) +#define IO_PORTX_INT_MII_TX_EOP (1 << 4) +#define IO_PORTX_INT_MII_COL (1 << 3) +#define IO_PORTX_INT_MII_CRS (1 << 2) +#define IO_PORTX_INT_MII_ODD_NIB_ERR (1 << 1) +#define IO_PORTX_INT_MII_FALSE_CARRIER (1 << 0) + +/* + * SerDes + */ +#define IO_PORTX_INT_SERDES_TXBUF_VALID (1 << 16) +#define IO_PORTX_INT_SERDES_RXERR (1 << 7) +#define IO_PORTX_INT_SERDES_RXEOP (1 << 6) +#define IO_PORTX_INT_SERDES_SYND (1 << 5) +#define IO_PORTX_INT_SERDES_TXBE (1 << 4) +#define IO_PORTX_INT_SERDES_TXEOP (1 << 3) +#define IO_PORTX_INT_SERDES_SXLP (1 << 2) +#define IO_PORTX_INT_SERDES_RXBF (1 << 1) +#define IO_PORTX_INT_SERDES_RXCRS (1 << 0) + +#ifndef __ASSEMBLY__ +struct ubicom32_io_port { + volatile u32_t function; + volatile u32_t gpio_ctl; + volatile u32_t gpio_out; + volatile u32_t gpio_in; + volatile u32_t int_status; + volatile u32_t int_mask; + volatile u32_t int_set; + volatile u32_t int_clr; + volatile u32_t tx_fifo; + volatile u32_t tx_fifo_hi; + volatile u32_t rx_fifo; + volatile u32_t rx_fifo_hi; + volatile u32_t ctl0; + volatile u32_t ctl1; + volatile u32_t ctl2; + volatile u32_t status0; + volatile u32_t status1; + volatile u32_t status2; + volatile u32_t fifo_watermark; + volatile u32_t fifo_level; + volatile u32_t gpio_mask; +}; + +#define UBICOM32_IO_PORT(port) ((struct ubicom32_io_port *)((port))) +#endif + +#ifndef __ASSEMBLY__ +/* + * ubicom32_set_interrupt() + */ +extern inline void ubicom32_set_interrupt(u8_t interrupt) +{ + u32_t ibit = INT_BIT_MASK(interrupt); + + if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) { + asm volatile ( + "move.4 "D(INT_SET(INT_CHIP(0, 0)))", %0\n\t" + : + : "r" (ibit) + ); + + return; + } + + asm volatile ( + "move.4 "D(INT_SET(INT_CHIP(1, 0)))", %0\n\t" + : + : "r" (ibit) + ); +} + +/* + * ubicom32_clear_interrupt() + */ +extern inline void ubicom32_clear_interrupt(u8_t interrupt) +{ + u32_t ibit = INT_BIT_MASK(interrupt); + + if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) { + asm volatile ( + "move.4 "D(INT_CLR(INT_CHIP(0, 0)))", %0\n\t" + : + : "r" (ibit) + ); + + return; + } + + asm volatile ( + "move.4 "D(INT_CLR(INT_CHIP(1, 0)))", %0\n\t" + : + : "r" (ibit) + ); +} + +/* + * ubicom32_enable_interrupt() + */ +extern inline void ubicom32_enable_interrupt(u8_t interrupt) +{ + u32_t ibit = INT_BIT_MASK(interrupt); + + if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) { + asm volatile ( + "or.4 "D(INT_MASK(INT_CHIP(0, 0)))", "D(INT_MASK(INT_CHIP(0, 0)))", %0\n\t" + : + : "d" (ibit) + ); + + return; + } + + asm volatile ( + "or.4 "D(INT_MASK(INT_CHIP(1, 0)))", "D(INT_MASK(INT_CHIP(1, 0)))", %0\n\t" + : + : "d" (ibit) + ); +} + +/* + * ubicom32_disable_interrupt() + */ +extern inline void ubicom32_disable_interrupt(u8_t interrupt) +{ + u32_t ibit = ~INT_BIT_MASK(interrupt); + + if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) { + asm volatile ( + "and.4 "D(INT_MASK(INT_CHIP(0, 0)))", "D(INT_MASK(INT_CHIP(0, 0)))", %0\n\t" + : + : "d" (ibit) + ); + + return; + } + + asm volatile ( + "and.4 "D(INT_MASK(INT_CHIP(1, 0)))", "D(INT_MASK(INT_CHIP(1, 0)))", %0\n\t" + : + : "d" (ibit) + ); +} + +/* + * ubicom32_enable_global_interrupts() + */ +extern inline void ubicom32_enable_global_interrupts(void) +{ + asm volatile( + "bset GLOBAL_CTRL, GLOBAL_CTRL, #%bit("D(GLOBAL_CTRL_INT_EN)")" + ); +} + +/* + * ubicom32_disable_global_interrupts() + */ +extern inline void ubicom32_disable_global_interrupts(void) +{ + asm volatile( + "bclr GLOBAL_CTRL, GLOBAL_CTRL, #%bit("D(GLOBAL_CTRL_INT_EN)")" + ); +} + +/* + * ubicom32_get_reset_reason() + */ +extern inline u32_t ubicom32_get_reset_reason(void) +{ + return *(u32_t *)(GENERAL_CFG_BASE + GEN_RESET_REASON); +} + +/* + * ubicom32_read_reg() + */ +extern inline u32_t ubicom32_read_reg(volatile void *reg) +{ + u32_t v; + asm volatile ( + "move.4 %[dest], %[src] \n\t" + : [dest] "=r" (v) + : [src] "m" (*(u32_t *)reg) + ); + return v; +} + +/* + * ubicom32_write_reg() + */ +extern inline void ubicom32_write_reg(volatile void *reg, u32_t v) +{ + asm volatile ( + "move.4 %[dest], %[src] \n\t" + : + : [src] "r" (v), [dest] "m" (*(u32_t *)reg) + ); +} + +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_UBICOM32_IP5000_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ipcbuf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ipcbuf.h new file mode 100644 index 000000000..76acafb20 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ipcbuf.h @@ -0,0 +1,55 @@ +/* + * arch/ubicom32/include/asm/ipcbuf.h + * Definition of ipc64_perm struct for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_IPCBUF_H +#define _ASM_UBICOM32_IPCBUF_H + +/* + * The user_ipc_perm structure for m68k architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit mode_t and seq + * - 2 miscellaneous 32-bit values + */ +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* _ASM_UBICOM32_IPCBUF_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq.h new file mode 100644 index 000000000..b5525894e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq.h @@ -0,0 +1,45 @@ +/* + * arch/ubicom32/include/asm/irq.h + * IRQ definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_IRQ_H +#define _ASM_UBICOM32_IRQ_H + +#include + +/* + * We setup the IRQS to cover the full range of interrupt registers in + * processor. + */ +#define NR_IRQS 64 + +#define irq_canonicalize(irq) (irq) + +extern int irq_soft_alloc(unsigned int *soft); +extern void ack_bad_irq(unsigned int irq); +extern void do_IRQ(int irq, struct pt_regs *fp); + +#endif /* _ASM_UBICOM32_IRQ_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq_regs.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq_regs.h new file mode 100644 index 000000000..afc33e40e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq_regs.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/irq_regs.h + * Generic irq_regs.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_IRQ_REGS_H +#define _ASM_UBICOM32_IRQ_REGS_H + +#include + +#endif /* _ASM_UBICOM32_IRQ_REGS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/irqflags.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/irqflags.h new file mode 100644 index 000000000..f40906e5a --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/irqflags.h @@ -0,0 +1,96 @@ +/* + * arch/ubicom32/include/asm/irqflags.h + * Raw implementation of local IRQ functions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_IRQFLAGS_H +#define _ASM_UBICOM32_IRQFLAGS_H + +#include +#include +#if defined(CONFIG_SMP) +#include +#endif +#include + +#if defined(CONFIG_PREEMPT) +#error Not supported by Ubicom32 irq handling, yet! +#endif + +/* + * raw_local_irq_enable() + * Enable interrupts for this thread. + */ +static inline void raw_local_irq_enable(void) +{ + ldsr_local_irq_enable(); +} + +/* + * raw_local_irq_disable() + * Disable interrupts for this thread. + */ +static inline void raw_local_irq_disable(void) +{ + ldsr_local_irq_disable(); +} + +/* + * raw_local_save_flags() + * Get the current IRQ state. + */ +#define raw_local_save_flags(flags) \ +do { \ + (flags) = ldsr_local_irq_is_disabled(); \ +} while (0) + +/* + * raw_local_irq_save() + * Save the current interrupt state and disable interrupts. + */ +#define raw_local_irq_save(flags) \ +do { \ + (flags) = ldsr_local_irq_save(); \ +} while (0) + +/* + * raw_local_irq_restore() + * Restore the IRQ state back to flags. + */ +static inline void raw_local_irq_restore(unsigned long flags) +{ + ldsr_local_irq_restore(flags); +} + +/* + * raw_irqs_disabled_flags() + * Return true if the flags indicate that IRQ(s) are disabled. + */ +static inline int raw_irqs_disabled_flags(unsigned long flags) +{ + return (flags); +} + +#endif /* _ASM_UBICOM32_IRQFLAGS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/kdebug.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/kdebug.h new file mode 100644 index 000000000..514bd2765 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/kdebug.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/kdebug.h + * Generic kdebug.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_KDEBUG_H +#define _ASM_UBICOM32_KDEBUG_H + +#include + +#endif /* _ASM_UBICOM32_KDEBUG_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/kmap_types.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/kmap_types.h new file mode 100644 index 000000000..5f4ffeacb --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/kmap_types.h @@ -0,0 +1,48 @@ +/* + * arch/ubicom32/include/asm/kmap_types.h + * Definition of km_type's for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_KMAP_TYPES_H +#define _ASM_UBICOM32_KMAP_TYPES_H + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + KM_TYPE_NR +}; + +#endif /* _ASM_UBICOM32_KMAP_TYPES_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ldsr.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ldsr.h new file mode 100644 index 000000000..b829c8790 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ldsr.h @@ -0,0 +1,186 @@ +/* + * arch/ubicom32/include/asm/ldsr.h + * Ubicom32 LDSR interface definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_LDSR_H +#define _ASM_UBICOM32_LDSR_H + +#include +#include +#include + +extern unsigned int ldsr_soft_irq_mask; + +/* + * ldsr_local_irq_is_disabled() + * Test if interrupts are disabled for this thread? + */ +static inline int ldsr_local_irq_is_disabled(void) +{ + int ret; + thread_t self = thread_get_self(); + unsigned int mask = (1 << self); + + asm volatile ( + " and.4 %0, scratchpad1, %1 \n\t" + : "=r" (ret) + : "d" (mask) + : "cc" + ); + + /* + * We return a simple 1 == disabled, 0 == enabled + * losing which tid this is for, because Linux + * can restore interrupts on a different thread. + */ + return ret >> self; +} + +/* + * ldsr_local_irq_save() + * Get the current interrupt state and disable interrupts. + */ +static inline unsigned int ldsr_local_irq_save(void) +{ + int ret; + thread_t self = thread_get_self(); + unsigned int mask = (1 << self); + + /* + * Ensure the compiler can not optimize out the code + * (volatile) and that it does not "cache" values around + * the interrupt state change (memory). This ensures + * that interrupt changes are treated as a critical + * section. + */ + asm volatile ( + " and.4 %0, scratchpad1, %1 \n\t" + " or.4 scratchpad1, scratchpad1, %1 \n\t" + : "=&r" (ret) + : "d" (mask) + : "cc", "memory" + ); + + /* + * We return a simple 1 == disabled, 0 == enabled + * losing which tid this is for, because Linux + * can restore interrupts on a different thread. + */ + return ret >> self; +} + +/* + * ldsr_local_irq_restore() + * Restore this cpu's interrupt enable/disable state. + * + * Note: flags is either 0 or 1. + */ +static inline void ldsr_local_irq_restore(unsigned int flags) +{ + unsigned int temp; + thread_t self = thread_get_self(); + unsigned int mask = (1 << self); + flags = (flags << self); + + /* + * Ensure the compiler can not optimize out the code + * (volatile) and that it does not "cache" values around + * the interrupt state change (memory). This ensures + * that interrupt changes are treated as a critical + * section. + * + * Atomic change to our bit in scratchpad1 without + * causing any temporary glitch in the value and + * without effecting other values. Also this uses + * no branches so no penalties. + */ + asm volatile ( + " xor.4 %0, scratchpad1, %1 \n\t" + " and.4 %0, %2, %0 \n\t" + " xor.4 scratchpad1, scratchpad1, %0 \n\t" + " move.4 int_set0, %3 \n\t" + : "=&d"(temp) + : "d"(flags), "r"(mask), "r"(ldsr_soft_irq_mask) + : "cc", "memory" + ); +} + +/* + * ldsr_local_irq_disable_interrupt() + * Disable ints for this thread. + */ +static inline void ldsr_local_irq_disable(void) +{ + unsigned int mask = (1 << thread_get_self()); + + /* + * Ensure the compiler can not optimize out the code + * (volatile) and that it does not "cache" values around + * the interrupt state change (memory). This ensures + * that interrupt changes are treated as a critical + * section. + */ + asm volatile ( + " or.4 scratchpad1, scratchpad1, %0 \n\t" + : + : "d" (mask) + : "cc", "memory" + ); +} + +/* + * ldsr_local_irq_enable_interrupt + * Enable ints for this thread. + */ +static inline void ldsr_local_irq_enable(void) +{ + unsigned int mask = (1 << thread_get_self()); + + /* + * Ensure the compiler can not optimize out the code + * (volatile) and that it does not "cache" values around + * the interrupt state change (memory). This ensures + * that interrupt changes are treated as a critical + * section. + */ + asm volatile ( + " and.4 scratchpad1, scratchpad1, %0 \n\t" + " move.4 int_set0, %1 \n\t" + : + : "d" (~mask), "r" (ldsr_soft_irq_mask) + : "cc", "memory" + ); +} + +extern void ldsr_init(void); +extern void ldsr_set_trap_irq(unsigned int irq); +extern void ldsr_mask_vector(unsigned int vector); +extern void ldsr_unmask_vector(unsigned int vector); +extern void ldsr_enable_vector(unsigned int vector); +extern void ldsr_disable_vector(unsigned int vector); +extern thread_t ldsr_get_threadid(void); + +#endif /* _ASM_UBICOM32_LDSR_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/linkage.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/linkage.h new file mode 100644 index 000000000..63d56a2c4 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/linkage.h @@ -0,0 +1,34 @@ +/* + * arch/ubicom32/include/asm/linkage.h + * Definition of Ubicom32 architecture specific linkage types. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_LINKAGE_H +#define _ASM_UBICOM32_LINKAGE_H + +#define __ocm_text __section(.ocm_text) +#define __ocm_data __section(.ocm_data) + +#endif /* _ASM_UBICOM32_LINKAGE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/local.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/local.h new file mode 100644 index 000000000..9c7931730 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/local.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/local.h + * Generic local.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_LOCAL_H +#define _ASM_UBICOM32_LOCAL_H + +#include + +#endif /* _ASM_UBICOM32_LOCAL_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/machdep.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/machdep.h new file mode 100644 index 000000000..c35815479 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/machdep.h @@ -0,0 +1,43 @@ +/* + * arch/ubicom32/include/asm/machdep.h + * Machine dependent utility routines. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_MACHDEP_H +#define _ASM_UBICOM32_MACHDEP_H + +#include + +/* Hardware clock functions */ +extern unsigned long hw_timer_offset(void); + +/* machine dependent power off functions */ +extern void (*mach_reset)(void); +extern void (*mach_halt)(void); +extern void (*mach_power_off)(void); + +extern void config_BSP(char *command, int len); + +#endif /* _ASM_UBICOM32_MACHDEP_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mc146818rtc.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mc146818rtc.h new file mode 100644 index 000000000..89b3c568b --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mc146818rtc.h @@ -0,0 +1,36 @@ +/* + * arch/ubicom32/include/asm/mc146818rtc.h + * Generic mc146818rtc.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +/* + * Machine dependent access functions for RTC registers. + */ +#ifndef _ASM_UBICOM32_MC146818RTC_H +#define _ASM_UBICOM32_MC146818RTC_H + +/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */ + +#endif /* _ASM_UBICOM32_MC146818RTC_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/memory_map.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/memory_map.h new file mode 100644 index 000000000..a1c3219b3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/memory_map.h @@ -0,0 +1,66 @@ +/* + * arch/ubicom32/include/asm/memory_map.h + * Machine memory maps/ + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_MEMORY_MAP_H +#define _ASM_UBICOM32_MEMORY_MAP_H + +/* + * Memory Size + */ +#define OCM_SECTOR_SIZE 0x00008000 /* 32K */ + +#if defined(CONFIG_UBICOM32_V3) +#define OCMSIZE 0x00030000 /* 192K on-chip RAM for both program and data */ +#elif defined(CONFIG_UBICOM32_V4) +#define OCMSIZE 0x0003C000 /* 240K on-chip RAM for both program and data */ +#else +#error "Unknown IP5K silicon" +#endif + +#define OCMSTART 0x3ffc0000 /* alias from 0x03000000 for easy + * jump to/from SDRAM */ +#define OCMEND (OCMSTART + OCMSIZE) + +#define SDRAMSTART 0x40000000 + +#define KERNELSTART (SDRAMSTART + 0x00400000) + +#define FLASHSTART 0x60000000 + +/* + * CODELOADER / OS_SYSCALL OCM Reservations + * Don't change these unless you know what you are doing. + */ +#define CODELOADER_SIZE 0x30 +#define CODELOADER_BEGIN OCMSTART /* Must be OCM start for gdb to work. */ +#define CODELOADER_END (CODELOADER_BEGIN + CODELOADER_SIZE) + +#define OS_SYSCALL_BEGIN CODELOADER_END /* system_call at this address */ +#define OS_SYSCALL_SIZE (512 - CODELOADER_SIZE) +#define OS_SYSCALL_END (OS_SYSCALL_BEGIN + OS_SYSCALL_SIZE) + +#endif /* _ASM_UBICOM32_MEMORY_MAP_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mman.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mman.h new file mode 100644 index 000000000..a2a3efe05 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mman.h @@ -0,0 +1,44 @@ +/* + * arch/ubicom32/include/asm/mman.h + * Memory mapping definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_MMAN_H +#define _ASM_UBICOM32_MMAN_H + +#include + +#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define MAP_LOCKED 0x2000 /* pages are locked */ +#define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ + +#define MCL_CURRENT 1 /* lock all current mappings */ +#define MCL_FUTURE 2 /* lock all future mappings */ + +#endif /* _ASM_UBICOM32_MMAN_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu.h new file mode 100644 index 000000000..71b604b52 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu.h @@ -0,0 +1,41 @@ +/* + * arch/ubicom32/include/asm/mmu.h + * Definition of mm_context_t struct for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2002, David McCullough + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_MMU_H +#define _ASM_UBICOM32_MMU_H + +typedef struct { + struct vm_list_struct *vmlist; + unsigned long end_brk; +#ifdef CONFIG_BINFMT_ELF_FDPIC + unsigned long exec_fdpic_loadmap; + unsigned long interp_fdpic_loadmap; +#endif +} mm_context_t; + +#endif /* _ASM_UBICOM32_MMU_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu_context.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu_context.h new file mode 100644 index 000000000..0123a6c91 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu_context.h @@ -0,0 +1,60 @@ +/* + * arch/ubicom32/include/asm/mmu_context.h + * MMU context definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2004, Microtronix Datacom Ltd., All rights reserved. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_MMU_CONTEXT_H +#define _ASM_UBICOM32_MMU_CONTEXT_H + +#include +#include +#include + +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ +} + +extern inline int +init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + // mm->context = virt_to_phys(mm->pgd); + return(0); +} + +#define destroy_context(mm) do { } while(0) + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) +{ +} + +#define deactivate_mm(tsk,mm) do { } while (0) + +extern inline void activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm) +{ +} + +#endif /* _ASM_UBICOM32_MMU_CONTEXT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/module.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/module.h new file mode 100644 index 000000000..1c891c674 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/module.h @@ -0,0 +1,48 @@ +/* + * arch/ubicom32/include/asm/module.h + * Ubicom32 architecture specific module definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_MODULE_H +#define _ASM_UBICOM32_MODULE_H + +struct mod_arch_specific { + void *ocm_inst; + int ocm_inst_size; +}; + +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr + +#define ARCH_PROC_MODULES_EXTRA(m,mod) \ + seq_printf(m, " OCM(%d bytes @ 0x%p)", \ + (mod)->arch.ocm_inst_size, (mod)->arch.ocm_inst) + +#define ARCH_OOPS_MODULE_EXTRA(mod) \ + printk(KERN_INFO "%p %u OCM(%p %u)\n", \ + (mod)->module_core, (mod)->core_size, \ + (mod)->arch.ocm_inst, (mod)->arch.ocm_inst_size) +#endif /* _ASM_UBICOM32_MODULE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/msgbuf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/msgbuf.h new file mode 100644 index 000000000..8d575e0f9 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/msgbuf.h @@ -0,0 +1,58 @@ +/* + * arch/ubicom32/include/asm/msgbuf.h + * Definition of msqid64_ds struct for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_MSGBUF_H +#define _ASM_UBICOM32_MSGBUF_H + +/* + * The msqid64_ds structure for ubicom32 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_time_t msg_stime; /* last msgsnd time */ + unsigned long __unused1; + __kernel_time_t msg_rtime; /* last msgrcv time */ + unsigned long __unused2; + __kernel_time_t msg_ctime; /* last change time */ + unsigned long __unused3; + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* _ASM_UBICOM32_MSGBUF_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mutex.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mutex.h new file mode 100644 index 000000000..5ab4de0da --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mutex.h @@ -0,0 +1,41 @@ +/* + * arch/ubicom32/include/asm/mutex.h + * Generic mutex.h for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +/* + * Pull in the generic implementation for the mutex fastpath. + * + * TODO: implement optimized primitives instead, or leave the generic + * implementation in place, or pick the atomic_xchg() based generic + * implementation. (see asm-generic/mutex-xchg.h for details) + */ + +#ifndef _ASM_UBICOM32_MUTEX_H +#define _ASM_UBICOM32_MUTEX_H + +#include + +#endif /* _ASM_UBICOM32_MUTEX_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/namei.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/namei.h new file mode 100644 index 000000000..8010c148f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/namei.h @@ -0,0 +1,38 @@ +/* + * arch/ubicom32/include/asm/namei.h + * Definition of __emul_prefix() for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_NAMEI_H +#define _ASM_UBICOM32_NAMEI_H + +/* This dummy routine maybe changed to something useful + * for /usr/gnemul/ emulation stuff. + * Look at asm-sparc/namei.h for details. + */ + +#define __emul_prefix() NULL + +#endif /* _ASM_UBICOM32_NAMEI_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm-alloc.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm-alloc.h new file mode 100644 index 000000000..ee29d8410 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm-alloc.h @@ -0,0 +1,36 @@ +/* + * arch/ubicom32/include/asm/ocm-alloc.h + * Ubicom32 architecture specific ocm definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_OCM_ALLOC_H +#define _ASM_UBICOM32_OCM_ALLOC_H + + +extern void *ocm_inst_alloc(size_t size, pid_t pid); +extern int ocm_free(const void *ptr); +extern int ocm_inst_free(const void *ptr); + +#endif /* _ASM_UBICOM32_OCM_ALLOC_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_size.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_size.h new file mode 100644 index 000000000..55778fe19 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_size.h @@ -0,0 +1,3 @@ +#define APP_OCM_CODE_SIZE (0x3ffc2e00-0x3ffc0000) +#define APP_OCM_DATA_SIZE (0x3ffd3500-0x3ffc8000) + diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_text.lds.inc b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_text.lds.inc new file mode 100644 index 000000000..5456cab55 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_text.lds.inc @@ -0,0 +1,175 @@ +/* + * arch/ubicom32/include/asm/ocm_text.lds.inc + * + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +*(.text.do_csum) +*(.text.tcp_packet) +*(.text.ipt_do_table) +*(.text.nf_conntrack_in) +*(.text.ip_forward) +*(.text.dev_queue_xmit) +*(.text.netif_receive_skb) +*(.text.ip_route_input) +*(.text.ip_finish_output) +*(.text.nf_iterate) +*(.text.__hash_conntrack) +*(.text.memset) +*(.text.memcpy) +*(.text.ip_rcv) +*(.text.__nf_conntrack_find) +*(.text.dev_hard_start_xmit) +*(.text.vlan_dev_hard_start_xmit) +*(.text.vlan_dev_hard_header) +*(.text.__nf_ct_refresh_acct) +*(.text.tcp_error) +*(.text.pfifo_fast_enqueue) +*(.text.ipv4_confirm) +*(.text.ip_output) +*(.text.neigh_connected_output) +*(.text.nf_hook_slow) +*(.text.nf_nat_packet) +*(.text.local_bh_enable) +*(.text.pfifo_fast_dequeue) +*(.text.ubi32_eth_receive) +*(.text.nf_nat_fn) +*(.text.skb_checksum) +*(.text.memmove) +*(.text.ubi32_eth_tx_done) +*(.text.eth_header) +*(.text.skb_release_data) +*(.text.nf_conntrack_find_get) +*(.text.process_backlog) +*(.text.vlan_skb_recv) +*(.text.ip_rcv_finish) +*(.text.__qdisc_run) +*(.text.skb_push) +*(.text.eth_type_trans) +*(.text.__alloc_skb) +*(.text.netif_rx) +*(.text.nf_ip_checksum) +*(.text.__skb_checksum_complete_head) +*(.text.ipv4_conntrack_defrag) +*(.text.tcp_pkt_to_tuple) +*(.text.kfree) +*(.text.tcp_manip_pkt) +*(.text.skb_put) +*(.text.nf_ct_get_tuple) +*(.text.__kmalloc) +*(.text.ubi32_eth_start_xmit) +*(.text.free_block) +*(.text.ipt_hook) +*(.text.kmem_cache_free) +*(.text.skb_pull_rcsum) +*(.text.cache_alloc_refill) +*(.text.skb_release_head_state) +*(.text.manip_pkt) +*(.text.ip_sabotage_in) +*(.text.ip_forward_finish) +*(.text.kmem_cache_alloc) +*(.text.local_bh_disable) +*(.text.ipv4_pkt_to_tuple) +*(.text.inet_proto_csum_replace4) +*(.text.__nf_ct_l4proto_find) +*(.text.csum_partial) +*(.text.neigh_resolve_output) +*(.text.__kfree_skb) +*(.text.kfree_skb) +*(.text.__find_vlan_dev) +*(.text.ldsr_ctxsw_thread) +*(.text.__do_IRQ) +*(.text.skb_pull) +*(.text.ipv4_invert_tuple) +*(.text.nf_ct_invert_tuplepr) +*(.text.skb_make_writable) +*(.text.ipv4_get_l4proto) +*(.text.handle_IRQ_event) +*(.text.net_rx_action) +*(.text.__do_softirq) +*(.text.nf_nat_in) +*(.text.note_interrupt) +*(.text.ipv4_conntrack_in) +*(.text.dst_release) +*(.text.tasklet_action) +*(.text.nf_nat_out) +*(.text.nf_ct_invert_tuple) +*(.text.do_IRQ) +*(.text.__tasklet_schedule) +*(.text.__skb_checksum_complete) +*(.text.ubi32_eth_interrupt) +*(.text.dev_kfree_skb_any) +*(.text.ret_from_interrupt_to_kernel) +*(.text.preemptive_context_save) +*(.text.irq_ack_vector) +*(.text.update_wall_time) +*(.text.ldsr_thread) +*(.text.irq_exit) +*(.text.ubi32_eth_do_tasklet) +*(.text.__napi_schedule) +*(.text.idle_cpu) +*(.text.run_timer_softirq) +*(.text.ldsr_mask_vector) +*(.text.irq_enter) +*(.text.ldsr_get_lsb) +*(.text.ldsr_unmask_vector) +*(.text.ip_fast_csum) +*(.text.hrtimer_run_queues) +*(.text.tcp_invert_tuple) +*(.text.T___705) +*(.text.run_posix_cpu_timers) +*(.text.free_hot_cold_page) +*(.text.lock_timer_base) +*(.text.calc_delta_mine) +*(.text.slab_destroy) +*(.text.rcu_pending) +*(.text.scheduler_tick) +*(.text.hrtimer_run_pending) +*(.text.do_softirq) +*(.text.del_timer) +*(.text.irq_end_vector) +*(.text.pci_read_u32) +*(.text.udivmodsi4) +*(.text.memcmp) +*(.text.memset) +*(.text.__slab_alloc) +*(.text.br_handle_frame) +*(.text.br_fdb_update) +*(.text.__br_fdb_get) +*(.text.br_forward) +*(.text.br_handle_frame_finish) +*(.text.pci_write_u32) +*(.text.kmem_freepages) +*(.text.br_dev_queue_push_xmit) +*(.text.ioread32) +*(.text.next_zones_zonelist) +*(.text.ubi32_pci_read_u32) +*(.text.zone_watermark_ok) +*(.text.__rmqueue_smallest) +*(.text.ubi32_eth_napi_poll) +*(.text.ubi32_pci_write_u32) +*(.text.ubi32_pci_read_u32) +*(.text._local_bh_enable) +*(.text._local_bh_disable) +*(.text.get_slab) diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/page.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/page.h new file mode 100644 index 000000000..1ecb174a6 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/page.h @@ -0,0 +1,116 @@ +/* + * arch/ubicom32/include/asm/page.h + * Memory page related operations and definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_PAGE_H +#define _ASM_UBICOM32_PAGE_H + +#include + +/* PAGE_SHIFT determines the page size */ + +#define PAGE_SHIFT (12) +#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#include + +#ifndef __ASSEMBLY__ + +#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) +#define free_user_page(page, addr) free_page(addr) + +#define clear_page(page) memset((page), 0, PAGE_SIZE) +#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \ + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr) +#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE + +/* + * These are used to make use of C type-checking.. + */ +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pmd[16]; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pgprot; } pgprot_t; +typedef struct page *pgtable_t; + +#define pte_val(x) ((x).pte) +#define pmd_val(x) ((&x)->pmd[0]) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pmd(x) ((pmd_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +extern unsigned long memory_start; +extern unsigned long memory_end; + +#endif /* !__ASSEMBLY__ */ + +#include + +#define PAGE_OFFSET (PAGE_OFFSET_RAW) + +#ifndef __ASSEMBLY__ + +#define __pa(vaddr) virt_to_phys((void *)(vaddr)) +#define __va(paddr) phys_to_virt((unsigned long)(paddr)) + +#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) +#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) + +#define virt_to_page(addr) (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) +#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) + +#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn)) +#define page_to_pfn(page) virt_to_pfn(page_to_virt(page)) +#define pfn_valid(pfn) ((pfn) < max_mapnr) + +#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ + ((void *)(kaddr) < (void *)memory_end)) + +#endif /* __ASSEMBLY__ */ + +#define VM_DATA_DEFAULT_FLAGS \ + (VM_READ | VM_WRITE | \ + ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) +#include +#else +#include +#endif + +#endif /* _ASM_UBICOM32_PAGE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/page_offset.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/page_offset.h new file mode 100644 index 000000000..8536568a9 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/page_offset.h @@ -0,0 +1,35 @@ +/* + * arch/ubicom32/include/asm/page_offset.h + * Definition of PAGE_OFFSET_RAW for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_PAGE_OFFSET_H +#define _ASM_UBICOM32_PAGE_OFFSET_H + +/* This handles the memory map.. */ +#define PAGE_OFFSET_RAW 0x3ffc0000 + +#endif /* _ASM_UBICOM32_PAGE_OFFSET_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/param.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/param.h new file mode 100644 index 000000000..00e5a7903 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/param.h @@ -0,0 +1,49 @@ +/* + * arch/ubicom32/include/asm/param.h + * Definition of miscellaneous constants, including HZ. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_PARAM_H +#define _ASM_UBICOM32_PARAM_H + +#ifdef __KERNEL__ +#define HZ CONFIG_HZ +#define USER_HZ HZ +#define CLOCKS_PER_SEC (USER_HZ) +#endif + +#ifndef HZ +#define HZ 100 +#endif + +#define EXEC_PAGESIZE 4096 + +#ifndef NOGROUP +#define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 /* max length of hostname */ + +#endif /* _ASM_UBICOM32_PARAM_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/pci.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pci.h new file mode 100644 index 000000000..0dce8bdc6 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pci.h @@ -0,0 +1,210 @@ +/* + * arch/ubicom32/include/asm/pci.h + * Definitions of PCI operations for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_PCI_H +#define _ASM_UBICOM32_PCI_H + +#include + +/* The PCI address space does equal the physical memory + * address space. The networking and block device layers use + * this boolean for bounce buffer decisions. + */ +#define PCI_DMA_BUS_IS_PHYS (1) + + + +/* + * Perform a master read/write to the PCI bus. + * These functions return a PCI_RESP_xxx code. + */ +extern u8 pci_read_u32(u8 pci_cmd, u32 address, u32 *data); +extern u8 pci_write_u32(u8 pci_cmd, u32 address, u32 data); +extern u8 pci_read_u16(u8 pci_cmd, u32 address, u16 *data); +extern u8 pci_write_u16(u8 pci_cmd, u32 address, u16 data); +extern u8 pci_read_u8(u8 pci_cmd, u32 address, u8 *data); +extern u8 pci_write_u8(u8 pci_cmd, u32 address, u8 data); + + +#define PCIBIOS_MIN_IO 0x100 +#define PCIBIOS_MIN_MEM 0x10000000 + +#define pcibios_assign_all_busses() 0 +#define pcibios_scan_all_fns(a, b) 0 +extern void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, + struct resource *res); + +extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, + struct pci_bus_region *region); + +struct pci_sys_data; +struct pci_bus; + +struct hw_pci { + struct list_head buses; + int nr_controllers; + int (*setup)(int nr, struct pci_sys_data *); + struct pci_bus *(*scan)(int nr, struct pci_sys_data *); + void (*preinit)(void); + void (*postinit)(void); + u8 (*swizzle)(struct pci_dev *dev, u8 *pin); + int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); +}; + +/* + * Per-controller structure + */ +struct pci_sys_data { + struct list_head node; + int busnr; /* primary bus number */ + u64 mem_offset; /* bus->cpu memory mapping offset */ + unsigned long io_offset; /* bus->cpu IO mapping offset */ + struct pci_bus *bus; /* PCI bus */ + struct resource *resource[3]; /* Primary PCI bus resources */ + /* Bridge swizzling */ + u8 (*swizzle)(struct pci_dev *, u8 *); + /* IRQ mapping */ + int (*map_irq)(struct pci_dev *, u8, u8); + struct hw_pci *hw; +}; + +static inline struct resource * +pcibios_select_root(struct pci_dev *pdev, struct resource *res) +{ + struct resource *root = NULL; + + if (res->flags & IORESOURCE_IO) + root = &ioport_resource; + if (res->flags & IORESOURCE_MEM) + root = &iomem_resource; + + return root; +} + +static inline void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} +#define HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE 1 +#define HAVE_ARCH_PCI_SET_DMA_SEGMENT_BOUNDARY 1 + +#ifdef CONFIG_PCI +static inline void * pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *vaddr = kmalloc(size, GFP_KERNEL); + if(vaddr != NULL) { + *dma_handle = virt_to_phys(vaddr); + } + return vaddr; +} + +static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + return 1; +} + +static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ + kfree(cpu_addr); + return; +} + +static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, + size_t size, int direction) +{ + return virt_to_phys(ptr); +} + +static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, + size_t size, int direction) +{ + return; +} + +static inline dma_addr_t +pci_map_page(struct pci_dev *hwdev, struct page *page, + unsigned long offset, size_t size, int direction) +{ + return pci_map_single(hwdev, page_address(page) + offset, size, (int)direction); +} + +static inline void +pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address, + size_t size, int direction) +{ + pci_unmap_single(hwdev, dma_address, size, direction); +} + +static inline int +pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, + int nents, int direction) +{ + return nents; +} + +static inline void +pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, + int nents, int direction) +{ +} + +static inline void +pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, + int nelems, int direction) +{ +} + +static inline void +pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, + int nelems, int direction) +{ +} + +static inline void +pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, + size_t size, int direction) +{ +} + +static inline void +pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, + size_t size, int direction) +{ +} + +static inline int +pci_dma_mapping_error(struct pci_dev *hwdev, dma_addr_t dma_addr) +{ + return dma_addr == 0; +} +extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); +extern void pci_iounmap(struct pci_dev *dev, void __iomem *); +#endif + +#endif /* _ASM_UBICOM32_PCI_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/pcm_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pcm_tio.h new file mode 100644 index 000000000..13b5fc1e8 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pcm_tio.h @@ -0,0 +1,84 @@ +/* + * arch/ubicom32/include/asm/pcm_tio.h + * Ubicom32 architecture PCM TIO definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#ifndef _ASM_UBICOM32_PCM_TIO_H +#define _ASM_UBICOM32_PCM_TIO_H + +#include + +#define PCM_TIO_REGS_VERSION 2 +struct pcm_tio_regs { + /* + * set this value to 1 to reload the parameters and restart the HRT + */ + u32_t reload; + + /* + * Pointers to the input and output buffers + */ + void *input_buf; + void *output_buf; + + /* + * Buffer size (see pcm_hrt.S for constraints) + */ + u32_t buffer_size; + + /* + * Current cycle. This variable increases every time half the buffer + * is consumed. + */ + u32_t cycle; + + /* + * Fields below this line are not accessed by the HRT. They are purely + * informational for the user of this TIO. + */ + + /* + * Version of this structure + */ + u32_t version; + + /* + * Number of channels supported + */ + u32_t channels; + + /* + * Maximum buffer size + */ + u32_t max_buffer_size; +}; + +/* + * Our device node + */ +#define PCM_TIO_NODE_VERSION 1 +struct pcm_tio_node { + struct devtree_node dn; + u32_t version; + struct pcm_tio_regs *regs; +}; + +#endif + diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/percpu.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/percpu.h new file mode 100644 index 000000000..4d51e6055 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/percpu.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/percpu.h + * Generic percpu.h for the Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_PERCPU_H +#define _ASM_UBICOM32_PERCPU_H + +#include + +#endif /* _ASM_UBICOM32_PERCPU_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgalloc.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgalloc.h new file mode 100644 index 000000000..397d19e41 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgalloc.h @@ -0,0 +1,36 @@ +/* + * arch/ubicom32/include/asm/pgalloc.h + * Page table allocation definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_PGALLOC_H +#define _ASM_UBICOM32_PGALLOC_H + +#include +#include + +#define check_pgt_cache() do { } while (0) + +#endif /* _ASM_UBICOM32_PGALLOC_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgtable.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgtable.h new file mode 100644 index 000000000..ffb30a9ec --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgtable.h @@ -0,0 +1,128 @@ +/* + * arch/ubicom32/include/asm/pgtable.h + * Ubicom32 pseudo page table definitions and operations. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * and various works, Alpha, ix86, M68K, Sparc, ...et al + */ +#ifndef _ASM_UBICOM32_PGTABLE_H +#define _ASM_UBICOM32_PGTABLE_H + +#include + +//vic - this bit copied from m68knommu version +#include +#include +#include + +typedef pte_t *pte_addr_t; + +#define pgd_present(pgd) (1) /* pages are always present on NO_MM */ +#define pgd_none(pgd) (0) +#define pgd_bad(pgd) (0) +#define pgd_clear(pgdp) +#define kern_addr_valid(addr) (1) +#define pmd_offset(a, b) ((void *)0) + +#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */ +//vic - this bit copied from m68knommu version + +extern void paging_init(void); +#define swapper_pg_dir ((pgd_t *) 0) + +#define __swp_type(x) (0) +#define __swp_offset(x) (0) +#define __swp_entry(typ,off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +/* + * pgprot_noncached() is only for infiniband pci support, and a real + * implementation for RAM would be more complicated. + */ +#define pgprot_noncached(prot) (prot) + +static inline int pte_file(pte_t pte) { return 0; } + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +#define ZERO_PAGE(vaddr) (virt_to_page(0)) + +extern unsigned int kobjsize(const void *objp); +extern int is_in_rom(unsigned long); + +/* + * No page table caches to initialise + */ +#define pgtable_cache_init() do { } while (0) + +#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ + remap_pfn_range(vma, vaddr, pfn, size, prot) + +extern inline void flush_cache_mm(struct mm_struct *mm) +{ +} + +extern inline void flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ +} + +/* Push the page at kernel virtual address and clear the icache */ +extern inline void flush_page_to_ram (unsigned long address) +{ +} + +/* Push n pages at kernel virtual address and clear the icache */ +extern inline void flush_pages_to_ram (unsigned long address, int n) +{ +} + +/* + * All 32bit addresses are effectively valid for vmalloc... + * Sort of meaningless for non-VM targets. + */ +#define VMALLOC_START 0 +#define VMALLOC_END 0xffffffff + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) +#include +#else +#define arch_enter_lazy_mmu_mode() do {} while (0) +#define arch_leave_lazy_mmu_mode() do {} while (0) +#define arch_flush_lazy_mmu_mode() do {} while (0) +#define arch_enter_lazy_cpu_mode() do {} while (0) +#define arch_leave_lazy_cpu_mode() do {} while (0) +#define arch_flush_lazy_cpu_mode() do {} while (0) +#endif + +#endif /* _ASM_UBICOM32_PGTABLE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/plio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/plio.h new file mode 100644 index 000000000..ade78f246 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/plio.h @@ -0,0 +1,313 @@ +/* + * plio.h + * PLIO defines. + * + * Copyright © 2009 Ubicom Inc. . All Rights Reserved. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 2 of the License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * This file contains confidential information of Ubicom, Inc. and your use of + * this file is subject to the Ubicom Software License Agreement distributed with + * this file. If you are uncertain whether you are an authorized user or to report + * any unauthorized use, please contact Ubicom, Inc. at +1-408-789-2200. + * Unauthorized reproduction or distribution of this file is subject to civil and + * criminal penalties. + */ + +#ifndef __PLIO__H__ +#define __PLIO__H__ + +#include +#include + +#define PLIO_PORT RD +#define PLIO_EXT_PORT RI + +#define TRANSMIT_FIFO_WATERMARK 8 + +/* + * PLIO non-blocking register definitions + */ +#define PLIO_FN 2 + +typedef struct { + unsigned : 10; + unsigned rxfifo_thread_enable: 1; /* allowed rxfifo thread enable */ + unsigned : 1; + unsigned rxfifo_thread: 4; /* allowed rxfifo thread access */ + unsigned : 4; + unsigned br_thread: 4; /* allowed blocking region thread access */ + unsigned fn_reset: 4; /* function reset bit vector */ + unsigned rxfifo_sel: 1; /* select between RXFIFO 0 and 1 */ + unsigned fn_sel: 3; /* select port function */ +} plio_io_function_t; + +typedef struct { + unsigned : 24; + unsigned pin:8; +} plio_gpio_t; + +typedef struct { + unsigned : 16; + unsigned txfifo_uf: 1; /* TXFIFO underflow */ + unsigned txfifo_wm: 1; /* TXFIFO watermark */ + unsigned rxfifo_of: 1; /* RXFIFO overflow */ + unsigned rxfifo_wm: 1; /* RXFIFO watermark */ + unsigned : 5; + unsigned lreg_int_addr_rd: 1; /* read from specified LREG address */ + unsigned lreg_int_addr_wr: 1; /* write to specified LREG address */ + unsigned extctl_int: 4; /* synchronized external interrupts */ + unsigned pfsm_int: 1; /* state machine */ +} plio_intstat_t; + +typedef struct { + unsigned txfifo_reset: 1; /* TXFIFO reset for int_set only */ + unsigned rxfifo_reset: 1; /* RXFIFO reset for int_set only */ + unsigned : 11; + unsigned idif_txfifo_flush: 1; /* flush TXFIFO and idif_txfifo */ + unsigned idif_rxfifo_flush: 1; /* flush RXFIFO and idif_rxfifo */ + unsigned pfsm_start: 1; /* input to fsm */ + unsigned txfifo_uf: 1; /* TXFIFO underflow */ + unsigned txfifo_wm: 1; /* TXFIFO watermark */ + unsigned rxfifo_of: 1; /* RXFIFO overflow */ + unsigned rxfifo_wm: 1; /* RXFIFO watermark */ + unsigned : 5; + unsigned lreg_int_addr_rd: 1; /* read from specified LREG address */ + unsigned lreg_int_addr_wr: 1; /* write to specified LREG address */ + unsigned extctl_int: 4; /* synchronized external interrupts */ + unsigned pfsm_int: 1; /* state machine */ +} plio_intset_t; + +typedef enum { + PLIO_PORT_MODE_D, + PLIO_PORT_MODE_DE, + PLIO_PORT_MODE_DI, + PLIO_PORT_MODE_DEI, + PLIO_PORT_MODE_DC, +} plio_port_mode_t; + +typedef enum { + PLIO_CLK_CORE, /* CORE CLK */ + PLIO_CLK_IO, /* IO CLK */ + PLIO_CLK_EXT, /* EXT CLK */ +} plio_clk_src_t; +typedef struct { + unsigned : 4; + unsigned edif_iaena_sel: 1; /* Input Address Enable Select */ + unsigned edif_iaclk_sel: 1; /* Input Address Clock Select */ + unsigned edif_iald_inv: 1; /* Input Address Strobe Invert */ + unsigned edif_idclk_sel: 1; /* Input Data Clock Select */ + unsigned edif_idld_inv: 1; /* Input Data Strobe Invert */ + unsigned edif_ds: 3; /* specify IDR and ODR data shift */ + unsigned edif_cmp_mode: 1; /* configure IDR comparator output */ + unsigned edif_idena_sel: 1; /* Input Data Enable Select */ + unsigned ecif_extclk_ena: 1; /* plio_extctl output select */ + unsigned idif_tx_fifo_cmd_sel: 1; /* select pfsm_cmd data word position */ + unsigned ptif_porti_cfg: 2; /* select port I pin configuration */ + unsigned ptif_portd_cfg: 3; /* select port D pin configuration */ + plio_port_mode_t ptif_port_mode: 3; /* select other plio ports */ + unsigned icif_clk_plio_ext_inv: 1; /* invert external plio clock when set */ + unsigned icif_rst_plio: 1; /* reset plio function and io fifos */ + plio_clk_src_t icif_clk_src_sel: 2; /* select plio clock source */ + unsigned pfsm_prog: 1; /* enable pfsm programming */ + unsigned pfsm_cmd: 3; /* software input to pfsm */ +} plio_fctl0_t; + +typedef struct { + unsigned : 2; + unsigned idif_byteswap_tx: 3; /* swap TXFIFO byte order */ + unsigned idif_byteswap_rx: 3; /* swap RXFIFO byte order */ + unsigned : 1; + unsigned lreg_ena: 1; /* enable local register map */ + unsigned lreg_addr_fifo_cmp_ena: 1; /* enable a specific LREG address from/to TX/RX fifos */ + unsigned lreg_addr_fifo_cmp: 5; /* LREG address routed from/to TX/RX fifos */ + unsigned : 1; + unsigned dcod_iald_idld_sel: 2; /* select address/data strobes */ + unsigned dcod_rw_src_sel: 1; /* select LREG strobe source */ + unsigned dcod_rd_sel: 5; /* select read strobe source */ + unsigned dcod_wr_sel: 5; /* select write strobe source */ + unsigned dcod_rd_lvl: 1; /* select active level of read strobe */ + unsigned dcod_wr_lvl: 1; /* select active level of read strobe */ +} plio_fctl1_t; + +typedef struct { + unsigned icif_eclk_div: 16; /* external plio clock divider */ + unsigned icif_iclk_div: 16; /* internal plio clock divider */ +} plio_fctl2_t; + +typedef struct { + unsigned : 27; + unsigned pfsm_state: 5; /* current pfsm state */ +} plio_stat_0_t; + +typedef struct { + unsigned : 3; + unsigned lreg_r_int_addr: 5; + unsigned : 11; + unsigned lreg_w_int_addr: 5; + unsigned lreg_w_int_data: 8; +} plio_stat_1_t; + +typedef struct { + unsigned : 32; +} plio_stat_2_t; + +typedef struct { + unsigned tx: 16; + unsigned rx: 16; +} plio_io_fifo_wm_t, plio_io_fifo_lvl_t; + + +/* plio blocking region register definitions + */ +typedef struct { + unsigned ns1: 5; + unsigned ic1: 7; + unsigned ec1: 4; + unsigned ns0: 5; + unsigned ic0: 7; + unsigned ec0: 4; +} plio_sram_t; + +typedef struct { + unsigned : 2; + unsigned s9: 3; + unsigned s8: 3; + unsigned s7: 3; + unsigned s6: 3; + unsigned s5: 3; + unsigned s4: 3; + unsigned s3: 3; + unsigned s2: 3; + unsigned s1: 3; + unsigned s0: 3; +} plio_grpsel_t; + +typedef struct { + unsigned s7: 4; + unsigned s6: 4; + unsigned s5: 4; + unsigned s4: 4; + unsigned s3: 4; + unsigned s2: 4; + unsigned s1: 4; + unsigned s0: 4; +} plio_cs_lut_t; + +typedef struct { + unsigned lut3: 8; + unsigned lut2: 8; + unsigned lut1: 8; + unsigned lut0: 8; +} plio_extctl_t; + +typedef struct { + plio_grpsel_t grpsel[4]; + u16_t cv[16]; + plio_cs_lut_t cs_lut[4]; + plio_extctl_t extctl_o_lut[8]; +} plio_pfsm_t; + +typedef struct { + u32_t odr_oe_sel; + u32_t odr_oe; + u32_t cmp; + u32_t ncmp; + u32_t cmp_mask; +} plio_edif_t; + +typedef enum { + PLIO_ECIF_CLK_OUT = 9, + PLIO_ECIF_IALD = 9, + PLIO_ECIF_CLK_IN = 8, + PLIO_ECIF_IDLD = 8, + PLIO_ECIF_INT = 2, +} plio_ecif_output_t; + +typedef struct { + u32_t bypass_sync; + u32_t ift; + u32_t output_type; + u32_t output_ena; + u32_t output_lvl; +} plio_ecif_t; + +typedef struct { + u32_t idr_addr_pos_mask; + u32_t reserved; + u32_t lreg_bar; +} plio_dcod_t; + +typedef struct { + u32_t addr_rd_ena; + u32_t addr_wr_ena; + u32_t addr_rd_int_ena; + u32_t addr_wr_int_ena; +} plio_lcfg_t; + + +/* + * PLIO configuration + */ +typedef struct { + plio_fctl0_t fctl0; + plio_fctl1_t fctl1; + plio_fctl2_t fctl2; +} plio_fctl_t; + +typedef struct { + plio_pfsm_t pfsm; + plio_edif_t edif; + plio_ecif_t ecif; + plio_dcod_t dcod; + plio_lcfg_t lcfg; +} plio_config_t; + +typedef struct { + plio_io_function_t function; + plio_gpio_t gpio_ctl; + plio_gpio_t gpio_out; + plio_gpio_t gpio_in; + plio_intstat_t intstat; + plio_intstat_t intmask; + plio_intset_t intset; + plio_intstat_t intclr; + unsigned tx_lo; + unsigned tx_hi; + unsigned rx_lo; + unsigned rx_hi; + plio_fctl0_t fctl0; + plio_fctl1_t fctl1; + plio_fctl2_t fctl2; + plio_stat_0_t stat0; + plio_stat_1_t stat1; + plio_stat_2_t stat2; + plio_io_fifo_wm_t fifo_wm; + plio_io_fifo_lvl_t fifo_lvl; +} plio_nbr_t; + +typedef struct { + u32_t pfsm_sram[256]; + plio_config_t config; +} plio_br_t; + +#define PLIO_NBR ((plio_nbr_t *)(PLIO_PORT)) +#define PLIO_BR ((plio_br_t *)((PLIO_PORT + IO_PORT_BR_OFFSET))) +#define PEXT_NBR ((plio_nbr_t *)(PLIO_EXT_PORT)) + +extern void plio_init(const plio_fctl_t *plio_fctl, const plio_config_t *plio_config, const plio_sram_t plio_sram_cfg[], int sram_cfg_size); + +#endif // __PLIO__H__ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/poll.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/poll.h new file mode 100644 index 000000000..8e92b7637 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/poll.h @@ -0,0 +1,36 @@ +/* + * arch/ubicom32/include/asm/poll.h + * Ubicom32 specific poll() related flags definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_POLL_H +#define _ASM_UBICOM32_POLL_H + +#define POLLWRNORM POLLOUT +#define POLLWRBAND 0x0100 + +#include + +#endif /* _ASM_UBICOM32_POLL_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/posix_types.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/posix_types.h new file mode 100644 index 000000000..40b69f851 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/posix_types.h @@ -0,0 +1,93 @@ +/* + * arch/ubicom32/include/asm/posix_types.h + * Ubicom32 architecture posix types. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef __ARCH_UBICOM32_POSIX_TYPES_H +#define __ARCH_UBICOM32_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +typedef unsigned short __kernel_old_dev_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) + +#undef __FD_CLR +#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) + +#undef __FD_ISSET +#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/processor.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/processor.h new file mode 100644 index 000000000..92e49e81a --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/processor.h @@ -0,0 +1,163 @@ +/* + * arch/ubicom32/include/asm/processor.h + * Thread related definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1995 Hamish Macdonald + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_PROCESSOR_H +#define _ASM_UBICOM32_PROCESSOR_H + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_UBICOM32_V3) + #define CPU "IP5K" +#endif +#if defined(CONFIG_UBICOM32_V4) + #define CPU "IP7K" +#endif +#ifndef CPU + #define CPU "UNKNOWN" +#endif + +/* + * User space process size: 1st byte beyond user address space. + */ +extern unsigned long memory_end; +#define TASK_SIZE (memory_end) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. We won't be using it + */ +#define TASK_UNMAPPED_BASE 0 + +/* + * This is the structure where we are going to save callee-saved registers. + * A5 is the return address, A7 is the stack pointer, A6 is the frame + * pointer. This is the frame that is created because of switch_to. This + * is not the frame due to interrupt preemption or because of syscall entry. + */ + +struct thread_struct { + unsigned long d10; /* D10 */ + unsigned long d11; /* D11 */ + unsigned long d12; /* D12 */ + unsigned long d13; /* D13 */ + unsigned long a1; /* A1 */ + unsigned long a2; /* A2 */ + unsigned long a5; /* A5 return address. */ + unsigned long a6; /* A6 */ + unsigned long sp; /* A7 kernel stack pointer. */ +}; + +#define INIT_THREAD { \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + sizeof(init_stack) + (unsigned long) init_stack - 8, \ +} + +/* + * Do necessary setup to start up a newly executed thread. + * + * pass the data segment into user programs if it exists, + * it can't hurt anything as far as I can tell + */ +/* + * Do necessary setup to start up a newly executed thread. + */ +#define start_thread(regs, new_pc, new_sp) \ + do { \ + regs->pc = new_pc & ~3; \ + regs->an[5] = new_pc & ~3; \ + regs->an[7] = new_sp; \ + regs->nesting_level = -1; \ + regs->frame_type = UBICOM32_FRAME_TYPE_NEW_THREAD; \ + regs->thread_type = NORMAL_THREAD; \ + } while(0) + +/* Forward declaration, a strange C thing */ +struct task_struct; + +/* Free all resources held by a thread. */ +static inline void release_thread(struct task_struct *dead_task) +{ +} + +/* Prepare to copy thread state - unlazy all lazy status */ +#define prepare_to_copy(tsk) do { } while (0) + +extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +/* + * Free current thread data structures etc.. + */ +static inline void exit_thread(void) +{ +} + +unsigned long thread_saved_pc(struct task_struct *tsk); +unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) (tsk->thread.a5) +#define KSTK_ESP(tsk) (tsk->thread.sp) + +#define cpu_relax() barrier() + +extern void processor_init(void); +extern unsigned int processor_timers(void); +extern unsigned int processor_threads(void); +extern unsigned int processor_frequency(void); +extern int processor_interrupts(unsigned int *int0, unsigned int *int1); +extern void processor_ocm(unsigned long *socm, unsigned long *eocm); +extern void processor_dram(unsigned long *sdram, unsigned long *edram); + +#define THREAD_SIZE_LONGS (THREAD_SIZE/sizeof(unsigned long)) +#define KSTK_TOP(info) \ +({ \ + unsigned long *__ptr = (unsigned long *)(info); \ + (unsigned long)(&__ptr[THREAD_SIZE_LONGS]); \ +}) + +#define task_pt_regs(task) \ +({ \ + struct pt_regs *__regs__; \ + __regs__ = (struct pt_regs *)(KSTK_TOP(task_stack_page(task))-8); \ + __regs__ - 1; \ +}) + +#endif /* _ASM_UBICOM32_PROCESSOR_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/profilesample.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/profilesample.h new file mode 100644 index 000000000..6e42269e3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/profilesample.h @@ -0,0 +1,44 @@ +/* + * arch/ubicom32/mach-common/profile.h + * Private data for the profile module + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + */ + + +#ifndef _PROFILESAMPLE_H_ +#define _PROFILESAMPLE_H_ + +/* + * a sample taken by the ipProfile package for sending to the profilertool + */ +struct profile_sample { + unsigned int pc; /* PC value */ + unsigned int a5; /* a5 contents for parent of leaf function */ + unsigned int parent; /* return address from stack, to find the caller */ + unsigned int latency; /* CPU clocks since the last message dispatch in this thread (thread 0 ony for now) */ + unsigned short active; /* which threads are active - for accurate counting */ + unsigned short d_blocked; /* which threads are blocked due to D cache misses */ + unsigned short i_blocked; /* which threads are blocked due to I cache misses */ + unsigned char cond_codes; /* for branch prediction */ + unsigned char thread; /* I-blocked, D-blocked, 4-bit thread number */ +}; + +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ptrace.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ptrace.h new file mode 100644 index 000000000..aeae2c78c --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ptrace.h @@ -0,0 +1,177 @@ +/* + * arch/ubicom32/include/asm/ptrace.h + * Ubicom32 architecture ptrace support. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_PTRACE_H +#define _ASM_UBICOM32_PTRACE_H + +#ifndef __ASSEMBLY__ + +/* + * We use hard coded constants because this is shared with user + * space and the values are NOT allowed to change. Only fields + * that are intended to be exposed get values. + */ +#define PT_D0 0 +#define PT_D1 4 +#define PT_D2 8 +#define PT_D3 12 +#define PT_D4 16 +#define PT_D5 20 +#define PT_D6 24 +#define PT_D7 28 +#define PT_D8 32 +#define PT_D9 36 +#define PT_D10 40 +#define PT_D11 44 +#define PT_D12 48 +#define PT_D13 52 +#define PT_D14 56 +#define PT_D15 60 +#define PT_A0 64 +#define PT_A1 68 +#define PT_A2 72 +#define PT_A3 76 +#define PT_A4 80 +#define PT_A5 84 +#define PT_A6 88 +#define PT_A7 92 +#define PT_SP 92 +#define PT_ACC0HI 96 +#define PT_ACC0LO 100 +#define PT_MAC_RC16 104 +#define PT_ACC1HI 108 +#define PT_ACC1LO 112 +#define PT_SOURCE3 116 +#define PT_INST_CNT 120 +#define PT_CSR 124 +#define PT_DUMMY_UNUSED 128 +#define PT_INT_MASK0 132 +#define PT_INT_MASK1 136 +#define PT_TRAP_CAUSE 140 +#define PT_PC 144 +#define PT_ORIGINAL_D0 148 +#define PT_FRAME_TYPE 152 + +/* + * The following 'registers' are not registers at all but are used + * locate the relocated sections. + */ +#define PT_TEXT_ADDR 200 +#define PT_TEXT_END_ADDR 204 +#define PT_DATA_ADDR 208 +#define PT_EXEC_FDPIC_LOADMAP 212 +#define PT_INTERP_FDPIC_LOADMAP 216 + +/* + * This struct defines the way the registers are stored on the + * stack during a system call. + */ +enum thread_type { + NORMAL_THREAD, + KERNEL_THREAD, +}; + +#define UBICOM32_FRAME_TYPE_SYSCALL -1 /* System call frame */ +#define UBICOM32_FRAME_TYPE_INVALID 0 /* Invalid frame, no longer in use */ +#define UBICOM32_FRAME_TYPE_INTERRUPT 1 /* Interrupt frame */ +#define UBICOM32_FRAME_TYPE_TRAP 2 /* Trap frame */ +#define UBICOM32_FRAME_TYPE_SIGTRAMP 3 /* Signal trampoline frame. */ +#define UBICOM32_FRAME_TYPE_NEW_THREAD 4 /* New Thread. */ + +struct pt_regs { + /* + * Data Registers + */ + unsigned long dn[16]; + + /* + * Address Registers + */ + unsigned long an[8]; + + /* + * Per thread misc registers. + */ + unsigned long acc0[2]; + unsigned long mac_rc16; + unsigned long acc1[2]; + unsigned long source3; + unsigned long inst_cnt; + unsigned long csr; + unsigned long dummy_unused; + unsigned long int_mask0; + unsigned long int_mask1; + unsigned long trap_cause; + unsigned long pc; + unsigned long original_dn_0; + + /* + * Frame type. Syscall frames are -1. For other types look above. + */ + unsigned long frame_type; + + /* + * These fields are not exposed to ptrace. + */ + unsigned long previous_pc; + long nesting_level; /* When the kernel in in user space this + * will be -1. */ + unsigned long thread_type; /* This indicates if this is a kernel + * thread. */ +}; + +/* + * This is the extended stack used by signal handlers and the context + * switcher: it's pushed after the normal "struct pt_regs". + */ +struct switch_stack { + unsigned long dummy; +}; + +#ifdef __KERNEL__ + +/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 + +#ifndef PS_S +#define PS_S (0x2000) +#define PS_M (0x1000) +#endif + +extern int __user_mode(unsigned long sp); + +#define user_mode(regs) (__user_mode((regs->an[7]))) +#define user_stack(regs) ((regs)->an[7]) +#define instruction_pointer(regs) ((regs)->pc) +#define profile_pc(regs) instruction_pointer(regs) +extern void show_regs(struct pt_regs *); +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_UBICOM32_PTRACE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect-asm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect-asm.h new file mode 100644 index 000000000..87459e4e9 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect-asm.h @@ -0,0 +1,91 @@ +/* + * arch/ubicom32/include/asm/range-protect-asm.h + * Assembly macros for enabling memory protection. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_RANGE_PROTECT_ASM_H +#define _ASM_UBICOM32_RANGE_PROTECT_ASM_H + +#if defined(__ASSEMBLY__) + +#include + +/* + * You should only use the enable/disable ranges when you have the atomic lock, + * if you do not there will be problems. + */ + +/* + * enable_kernel_ranges + * Enable the kernel ranges (disabling protection) for thread, + * where thread == (1 << thread number) + */ +.macro enable_kernel_ranges thread +#ifdef CONFIG_PROTECT_KERNEL + or.4 I_RANGE0_EN, I_RANGE0_EN, \thread /* Enable Range Register */ + or.4 D_RANGE0_EN, D_RANGE0_EN, \thread + or.4 D_RANGE1_EN, D_RANGE1_EN, \thread +#endif +.endm + +/* + * enable_kernel_ranges_for_current + * Enable the kernel ranges (disabling protection) for this thread + */ +.macro enable_kernel_ranges_for_current scratch_reg +#ifdef CONFIG_PROTECT_KERNEL + thread_get_self_mask \scratch_reg + enable_kernel_ranges \scratch_reg +#endif +.endm + +/* + * disable_kernel_ranges + * Disables the kernel ranges (enabling protection) for thread + * where thread == (1 << thread number) + */ +.macro disable_kernel_ranges thread +#ifdef CONFIG_PROTECT_KERNEL + not.4 \thread, \thread + and.4 I_RANGE0_EN, I_RANGE0_EN, \thread /* Disable Range Register */ + and.4 D_RANGE0_EN, D_RANGE0_EN, \thread + and.4 D_RANGE1_EN, D_RANGE1_EN, \thread +#endif +.endm + +/* + * disable_kernel_ranges_for_current + * Disable kernel ranges (enabling protection) for this thread + */ +.macro disable_kernel_ranges_for_current scratch_reg +#ifdef CONFIG_PROTECT_KERNEL + thread_get_self_mask \scratch_reg + disable_kernel_ranges \scratch_reg +#endif +.endm +#endif + +#endif /* _ASM_UBICOM32_RANGE_PROTECT_ASM_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect.h new file mode 100644 index 000000000..b4bd2f043 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect.h @@ -0,0 +1,62 @@ +/* + * arch/ubicom32/include/asm/range-protect.h + * Assembly macros declared in C for enabling memory protection. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_RANGE_PROTECT_H +#define _ASM_UBICOM32_RANGE_PROTECT_H + +#if !defined(__ASSEMBLY__) +#include +/* + * The following macros should be the identical to the ones in + * range-protect-asm.h + * + * You should only use the enable/disable ranges when you have the atomic lock, + * if you do not there will be problems. + */ + +/* + * enable_kernel_ranges + * Enable the kernel ranges (disabling protection) for thread, + * where thread == (1 << thread number) + */ +asm ( + ".macro enable_kernel_ranges thread \n\t" +#ifdef CONFIG_PROTECT_KERNEL + " or.4 I_RANGE0_EN, I_RANGE0_EN, \\thread \n\t" /* Enable Range Register */ + " or.4 D_RANGE0_EN, D_RANGE0_EN, \\thread \n\t" + " or.4 D_RANGE1_EN, D_RANGE1_EN, \\thread \n\t" +#endif + ".endm \n\t" +); + +#else /* __ASSEMBLY__ */ + +#include + +#endif +#endif /* _ASM_UBICOM32_RANGE_PROTECT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/resource.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/resource.h new file mode 100644 index 000000000..0a59a4f25 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/resource.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/resource.h + * Generic definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_RESOURCE_H +#define _ASM_UBICOM32_RESOURCE_H + +#include + +#endif /* _ASM_UBICOM32_RESOURCE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ring_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ring_tio.h new file mode 100644 index 000000000..c02a44520 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ring_tio.h @@ -0,0 +1,42 @@ +/* + * arch/ubicom32/include/asm/ring_tio.h + * Ubicom32 architecture Ring TIO definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#ifndef _ASM_UBICOM32_RING_TIO_H +#define _ASM_UBICOM32_RING_TIO_H + +#include + +#define RING_TIO_NODE_VERSION 2 + +/* + * Devtree node for ring + */ +struct ring_tio_node { + struct devtree_node dn; + + u32_t version; + void *regs; +}; + +extern void ring_tio_init(const char *node_name); + +#endif /* _ASM_UBICOM32_RING_TIO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/scatterlist.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/scatterlist.h new file mode 100644 index 000000000..4fb4df171 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/scatterlist.h @@ -0,0 +1,49 @@ +/* + * arch/ubicom32/include/asm/scatterlist.h + * Definitions of struct scatterlist for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SCATTERLIST_H +#define _ASM_UBICOM32_SCATTERLIST_H + +#include +#include + +struct scatterlist { +#ifdef CONFIG_DEBUG_SG + unsigned long sg_magic; +#endif + unsigned long page_link; + unsigned int offset; + dma_addr_t dma_address; + unsigned int length; +}; + +#define sg_dma_address(sg) ((sg)->dma_address) +#define sg_dma_len(sg) ((sg)->length) + +#define ISA_DMA_THRESHOLD (0xffffffff) + +#endif /* _ASM_UBICOM32_SCATTERLIST_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sd_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sd_tio.h new file mode 100644 index 000000000..ecb2b8272 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sd_tio.h @@ -0,0 +1,36 @@ +/* + * arch/ubicom32/include/asm/sd_tio.h + * SD TIO definitions + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#ifndef _ASM_UBICOM32_SD_TIO_H +#define _ASM_UBICOM32_SD_TIO_H + +#include + +/* + * Devtree node for SD + */ +struct sd_tio_node { + struct devtree_node dn; + void *regs; +}; + +#endif /* _ASM_UBICOM32_SD_TIO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sections.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sections.h new file mode 100644 index 000000000..eb7d24bc2 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sections.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/sections.h + * Generic sections.h definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SECTIONS_H +#define _ASM_UBICOM32_SECTIONS_H + +#include + +#endif /* _ASM_UBICOM32_SECTIONS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/segment.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/segment.h new file mode 100644 index 000000000..3f1049076 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/segment.h @@ -0,0 +1,78 @@ +/* + * arch/ubicom32/include/asm/segment.h + * Memory segment definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SEGMENT_H +#define _ASM_UBICOM32_SEGMENT_H + +/* define constants */ +/* Address spaces (FC0-FC2) */ +#define USER_DATA (1) +#ifndef __USER_DS +#define __USER_DS (USER_DATA) +#endif +#define USER_PROGRAM (2) +#define SUPER_DATA (5) +#ifndef __KERNEL_DS +#define __KERNEL_DS (SUPER_DATA) +#endif +#define SUPER_PROGRAM (6) +#define CPU_SPACE (7) + +#ifndef __ASSEMBLY__ + +typedef struct { + unsigned long seg; +} mm_segment_t; + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) +#define USER_DS MAKE_MM_SEG(__USER_DS) +#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS) + +/* + * Get/set the SFC/DFC registers for MOVES instructions + */ + +static inline mm_segment_t get_fs(void) +{ + return USER_DS; +} + +static inline mm_segment_t get_ds(void) +{ + /* return the supervisor data space code */ + return KERNEL_DS; +} + +static inline void set_fs(mm_segment_t val) +{ +} + +#define segment_eq(a,b) ((a).seg == (b).seg) + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_UBICOM32_SEGMENT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore-helper.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore-helper.h new file mode 100644 index 000000000..ad0aaf0a2 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore-helper.h @@ -0,0 +1,109 @@ +/* + * arch/ubicom32/include/asm/semaphore-helper.h + * Semaphore related definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SEMAPHORE_HELPER_H +#define _ASM_UBICOM32_SEMAPHORE_HELPER_H + +/* + * SMP- and interrupt-safe semaphores helper functions. + * + * (C) Copyright 1996 Linus Torvalds + * + * m68k version by Andreas Schwab + */ + + +/* + * These two _must_ execute atomically wrt each other. + */ +static inline void wake_one_more(struct semaphore * sem) +{ + atomic_inc(&sem->waking); +} + +static inline int waking_non_zero(struct semaphore *sem) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + ret = 0; + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking_non_zero_interruptible: + * 1 got the lock + * 0 go to sleep + * -EINTR interrupted + */ +static inline int waking_non_zero_interruptible(struct semaphore *sem, + struct task_struct *tsk) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + ret = 0; + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } else if (signal_pending(tsk)) { + atomic_inc(&sem->count); + ret = -EINTR; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking_non_zero_trylock: + * 1 failed to lock + * 0 got the lock + */ +static inline int waking_non_zero_trylock(struct semaphore *sem) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + ret = 1; + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 0; + } else + atomic_inc(&sem->count); + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +#endif /* _ASM_UBICOM32_SEMAPHORE_HELPER_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore.h new file mode 100644 index 000000000..d20ead310 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore.h @@ -0,0 +1,140 @@ +/* + * arch/ubicom32/include/asm/semaphore.h + * Interrupt-safe semaphores for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * (C) Copyright 1996 Linus Torvalds + * m68k version by Andreas Schwab + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SEMAPHORE_H +#define _ASM_UBICOM32_SEMAPHORE_H + +#define RW_LOCK_BIAS 0x01000000 + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +#include +#include + +struct semaphore { + atomic_t count; + atomic_t waking; + wait_queue_head_t wait; +}; + +#define __SEMAPHORE_INITIALIZER(name, n) \ +{ \ + .count = ATOMIC_INIT(n), \ + .waking = ATOMIC_INIT(0), \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ +} + +#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) + +#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) +#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) + +static inline void sema_init (struct semaphore *sem, int val) +{ + *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); +} + +static inline void init_MUTEX (struct semaphore *sem) +{ + sema_init(sem, 1); +} + +static inline void init_MUTEX_LOCKED (struct semaphore *sem) +{ + sema_init(sem, 0); +} + +asmlinkage void __down_failed(void /* special register calling convention */); +asmlinkage int __down_failed_interruptible(void /* params in registers */); +asmlinkage int __down_failed_trylock(void /* params in registers */); +asmlinkage void __up_wakeup(void /* special register calling convention */); + +asmlinkage void __down(struct semaphore * sem); +asmlinkage int __down_interruptible(struct semaphore * sem); +asmlinkage int __down_trylock(struct semaphore * sem); +asmlinkage void __up(struct semaphore * sem); + +extern spinlock_t semaphore_wake_lock; + +/* + * This is ugly, but we want the default case to fall through. + * "down_failed" is a special asm handler that calls the C + * routine that actually waits. + */ +static inline void down(struct semaphore * sem) +{ + might_sleep(); + + if (atomic_dec_return(&sem->count) < 0) + __down(sem); +} + +static inline int down_interruptible(struct semaphore * sem) +{ + int ret = 0; + + + might_sleep(); + + if(atomic_dec_return(&sem->count) < 0) + ret = __down_interruptible(sem); + return ret; +} + +static inline int down_trylock(struct semaphore * sem) +{ + int ret = 0; + + if (atomic_dec_return (&sem->count) < 0) + ret = __down_trylock(sem); + return ret; +} + +/* + * Note! This is subtle. We jump to wake people up only if + * the semaphore was negative (== somebody was waiting on it). + * The default case (no contention) will result in NO + * jumps for both down() and up(). + */ +static inline void up(struct semaphore * sem) +{ + if (atomic_inc_return(&sem->count) <= 0) + __up(sem); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_UBICOM32_SEMAPHORE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sembuf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sembuf.h new file mode 100644 index 000000000..996a7a011 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sembuf.h @@ -0,0 +1,52 @@ +/* + * arch/ubicom32/include/asm/sembuf.h + * The semid64_ds structure for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SEMBUF_H +#define _ASM_UBICOM32_SEMBUF_H + +/* + * The semid64_ds structure for ubicom32 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t sem_otime; /* last semop time */ + unsigned long __unused1; + __kernel_time_t sem_ctime; /* last change time */ + unsigned long __unused2; + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* _ASM_UBICOM32_SEMBUF_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/setup.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/setup.h new file mode 100644 index 000000000..ad8dc5760 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/setup.h @@ -0,0 +1,35 @@ +/* + * arch/ubicom32/include/asm/setup.h + * Kernel command line length definition. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2004, Microtronix Datacom Ltd., All rights reserved. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_SETUP_H +#define _ASM_UBICOM32_SETUP_H + +#define COMMAND_LINE_SIZE 512 + +#endif /* _ASM_UBICOM32_SETUP_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmbuf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmbuf.h new file mode 100644 index 000000000..7cc433966 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmbuf.h @@ -0,0 +1,69 @@ +/* + * arch/ubicom32/include/asm/shmbuf.h + * The shmid64_ds structure for the Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SHMBUF_H +#define _ASM_UBICOM32_SHMBUF_H + +/* + * The shmid64_ds structure for m68k architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + unsigned long __unused1; + __kernel_time_t shm_dtime; /* last detach time */ + unsigned long __unused2; + __kernel_time_t shm_ctime; /* last change time */ + unsigned long __unused3; + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused4; + unsigned long __unused5; +}; + +struct shminfo64 { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* _ASM_UBICOM32_SHMBUF_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmparam.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmparam.h new file mode 100644 index 000000000..851d06270 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmparam.h @@ -0,0 +1,35 @@ +/* + * arch/ubicom32/include/asm/shmparam.h + * Shared memory definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * Alpha, ix86, M68K, Sparc, ...et al + */ +#ifndef _ASM_UBICOM32_SHMPARAM_H +#define _ASM_UBICOM32_SHMPARAM_H + +#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ + +#endif /* _ASM_UBICOM32_SHMPARAM_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sigcontext.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sigcontext.h new file mode 100644 index 000000000..8bbeb82a7 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sigcontext.h @@ -0,0 +1,37 @@ +/* + * arch/ubicom32/include/asm/sigcontext.h + * Definition of sigcontext struct for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SIGCONTEXT_H +#define _ASM_UBICOM32_SIGCONTEXT_H + +#include + +struct sigcontext { + struct pt_regs sc_regs; +}; + +#endif /* _ASM_UBICOM32_SIGCONTEXT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/siginfo.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/siginfo.h new file mode 100644 index 000000000..be0a4653c --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/siginfo.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/siginfo.h + * Generic siginfo.h definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SIGINFO_H +#define _ASM_UBICOM32_SIGINFO_H + +#include + +#endif /* _ASM_UBICOM32_SIGINFO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/signal.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/signal.h new file mode 100644 index 000000000..946b3f77d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/signal.h @@ -0,0 +1,185 @@ +/* + * arch/ubicom32/include/asm/signal.h + * Signal related definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SIGNAL_H +#define _ASM_UBICOM32_SIGNAL_H + +#include + +/* Avoid too many header ordering problems. */ +struct siginfo; + +#ifdef __KERNEL__ +/* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#endif /* __KERNEL__ */ + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX _NSIG + +/* + * SA_FLAGS values: + * + * SA_ONSTACK indicates that a registered stack_t will be used. + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 +#define SA_SIGINFO 0x00000004 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 + +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) +#include +#else +#include +#endif + +#ifdef __KERNEL__ +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; +}; +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +struct sigaction { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +#define sa_handler _u._sa_handler +#define sa_sigaction _u._sa_sigaction + +#endif /* __KERNEL__ */ + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +#ifdef __KERNEL__ + +#include +#undef __HAVE_ARCH_SIG_BITOPS + +#define ptrace_signal_deliver(regs, cookie) do { } while (0) + +#endif /* __KERNEL__ */ + +#endif /* _ASM_UBICOM32_SIGNAL_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/smp.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/smp.h new file mode 100644 index 000000000..651a53695 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/smp.h @@ -0,0 +1,87 @@ +/* + * arch/ubicom32/include/asm/smp.h + * SMP definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SMP_H +#define _ASM_UBICOM32_SMP_H + +#ifndef CONFIG_SMP +#error you should not include smp.h if smp is off +#endif + +#ifndef ASSEMBLY +#include +#include +#include +#include + +typedef unsigned long address_t; +extern unsigned int smp_ipi_irq; + +/* + * This magic constant controls our willingness to transfer + * a process across CPUs. + * + * Such a transfer incurs cache and tlb + * misses. The current value is inherited from i386. Still needs + * to be tuned for parisc. + */ +#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */ +#define NO_PROC_ID 0xFF /* No processor magic marker */ +#define ANY_PROC_ID 0xFF /* Any processor magic marker */ + +#ifdef CONFIG_SMP +#define raw_smp_processor_id() (current_thread_info()->cpu) +#endif /* CONFIG_SMP */ + +static inline int __cpu_disable (void) +{ + return 0; +} + +static inline void __cpu_die (unsigned int cpu) +{ + while(1) { + }; +} + +extern int __cpu_up(unsigned int cpu); +extern void smp_send_timer_all(void); +extern void smp_timer_broadcast(const struct cpumask *mask); +extern void smp_set_affinity(unsigned int irq, const struct cpumask *dest); +extern void arch_send_call_function_single_ipi(int cpu); +#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask +extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); + +/* + * TODO: Once these are fully tested, we should turn them into + * inline macros for performance. + */ +extern unsigned long smp_get_affinity(unsigned int irq, int *all); +extern void smp_reset_ipi(unsigned long mask); + +#endif /* !ASSEMBLY */ +#endif /* _ASM_UBICOM32_SMP_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/socket.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/socket.h new file mode 100644 index 000000000..24ac11314 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/socket.h @@ -0,0 +1,90 @@ +/* + * arch/ubicom32/include/asm/socket.h + * Socket options definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SOCKET_H +#define _ASM_UBICOM32_SOCKET_H + +#include + +/* For setsockopt(2) */ +#define SOL_SOCKET 1 + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +/* To add :#define SO_REUSEPORT 15 */ +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +/* Security levels - as per NRL IPv6 - don't actually do anything */ +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +/* Socket filtering */ +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 + +#define SO_PEERNAME 28 +#define SO_TIMESTAMP 29 +#define SCM_TIMESTAMP SO_TIMESTAMP + +#define SO_ACCEPTCONN 30 + +#define SO_PEERSEC 31 +#define SO_PASSSEC 34 +#define SO_TIMESTAMPNS 35 +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS + +#define SO_MARK 36 + +#define SO_TIMESTAMPING 37 +#define SCM_TIMESTAMPING SO_TIMESTAMPING + +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 + +#endif /* _ASM_UBICOM32_SOCKET_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sockios.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sockios.h new file mode 100644 index 000000000..5a7708d96 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sockios.h @@ -0,0 +1,40 @@ +/* + * arch/ubicom32/include/asm/sockios.h + * Socket-level ioctl definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SOCKIOS_H +#define _ASM_UBICOM32_SOCKIOS_H + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ +#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ + +#endif /* _ASM_UBICOM32_SOCKIOS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock.h new file mode 100644 index 000000000..40080584c --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock.h @@ -0,0 +1,296 @@ +/* + * arch/ubicom32/include/asm/spinlock.h + * Spinlock related definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SPINLOCK_H +#define _ASM_UBICOM32_SPINLOCK_H + +#include +#include +#include + +/* + * __raw_spin_lock() + * Lock the lock. + */ +static inline void __raw_spin_lock(raw_spinlock_t *x) +{ + asm volatile ( + "1: bset %0, %0, #0 \n\t" + " jmpne.f 1b \n\t" + : "+U4" (x->lock) + : + : "memory", "cc" + ); +} + +/* + * __raw_spin_unlock() + * Unlock the lock. + */ +static inline void __raw_spin_unlock(raw_spinlock_t *x) +{ + asm volatile ( + " bclr %0, %0, #0 \n\t" + : "+U4" (x->lock) + : + : "memory", "cc" + ); +} + +/* + * __raw_spin_is_locked() + * Test if the lock is locked. + */ +static inline int __raw_spin_is_locked(raw_spinlock_t *x) +{ + return x->lock; +} + +/* + * __raw_spin_unlock_wait() + * Wait for the lock to be unlocked. + * + * Note: the caller has not guarantee that the lock will not + * be acquired before they get to it. + */ +static inline void __raw_spin_unlock_wait(raw_spinlock_t *x) +{ + do { + cpu_relax(); + } while (__raw_spin_is_locked(x)); +} + +/* + * __raw_spin_trylock() + * Try the lock, return 0 on failure, 1 on success. + */ +static inline int __raw_spin_trylock(raw_spinlock_t *x) +{ + int ret = 0; + + asm volatile ( + " bset %1, %1, #0 \n\t" + " jmpne.f 1f \n\t" + " move.4 %0, #1 \n\t" + "1: \n\t" + : "+r" (ret), "+U4" (x->lock) + : + : "memory", "cc" + ); + + return ret; +} + +/* + * __raw_spin_lock_flags() + * Spin waiting for the lock (enabling IRQ(s)) + */ +static inline void __raw_spin_lock_flags(raw_spinlock_t *x, unsigned long flags) +{ + mb(); + while (!__raw_spin_trylock(x)) { + /* + * If the flags from the IRQ are set, interrupts are disabled and we + * need to re-enable them. + */ + if (!flags) { + cpu_relax(); + } else { + raw_local_irq_enable(); + cpu_relax(); + raw_local_irq_disable(); + } + } + mb(); +} + +/* + * Read-write spinlocks, allowing multiple readers but only one writer. + * Linux rwlocks are unfair to writers; they can be starved for an indefinite + * time by readers. With care, they can also be taken in interrupt context. + * + * In Ubicom32 architecture implementation, we have a spinlock and a counter. + * Readers use the lock to serialise their access to the counter (which + * records how many readers currently hold the lock). + * Writers hold the spinlock, preventing any readers or other writers from + * grabbing the rwlock. + */ + +/* + * __raw_read_lock() + * Increment the counter in the rwlock. + * + * Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to grab the same read lock + */ +static inline void __raw_read_lock(raw_rwlock_t *rw) +{ + unsigned long flags; + raw_local_irq_save(flags); + __raw_spin_lock_flags(&rw->lock, flags); + rw->counter++; + __raw_spin_unlock(&rw->lock); + raw_local_irq_restore(flags); +} + +/* + * __raw_read_unlock() + * Decrement the counter. + * + * Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to grab the same read lock + */ +static inline void __raw_read_unlock(raw_rwlock_t *rw) +{ + unsigned long flags; + raw_local_irq_save(flags); + __raw_spin_lock_flags(&rw->lock, flags); + rw->counter--; + __raw_spin_unlock(&rw->lock); + raw_local_irq_restore(flags); +} + +/* + * __raw_read_trylock() + * Increment the counter if we can. + * + * Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to grab the same read lock + */ +static inline int __raw_read_trylock(raw_rwlock_t *rw) +{ + unsigned long flags; + retry: + raw_local_irq_save(flags); + if (__raw_spin_trylock(&rw->lock)) { + rw->counter++; + __raw_spin_unlock(&rw->lock); + raw_local_irq_restore(flags); + return 1; + } + + raw_local_irq_restore(flags); + + /* + * If write-locked, we fail to acquire the lock + */ + if (rw->counter < 0) { + return 0; + } + + /* + * Wait until we have a realistic chance at the lock + */ + while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0) { + cpu_relax(); + } + + goto retry; +} + +/* + * __raw_write_lock() + * + * Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to read_trylock() this lock + */ +static inline void __raw_write_lock(raw_rwlock_t *rw) +{ + unsigned long flags; +retry: + raw_local_irq_save(flags); + __raw_spin_lock_flags(&rw->lock, flags); + + if (rw->counter != 0) { + __raw_spin_unlock(&rw->lock); + raw_local_irq_restore(flags); + + while (rw->counter != 0) + cpu_relax(); + + goto retry; + } + + rw->counter = -1; /* mark as write-locked */ + mb(); + raw_local_irq_restore(flags); +} + +static inline void __raw_write_unlock(raw_rwlock_t *rw) +{ + rw->counter = 0; + __raw_spin_unlock(&rw->lock); +} + +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to read_trylock() this lock */ +static inline int __raw_write_trylock(raw_rwlock_t *rw) +{ + unsigned long flags; + int result = 0; + + raw_local_irq_save(flags); + if (__raw_spin_trylock(&rw->lock)) { + if (rw->counter == 0) { + rw->counter = -1; + result = 1; + } else { + /* Read-locked. Oh well. */ + __raw_spin_unlock(&rw->lock); + } + } + raw_local_irq_restore(flags); + + return result; +} + +/* + * read_can_lock - would read_trylock() succeed? + * @lock: the rwlock in question. + */ +static inline int __raw_read_can_lock(raw_rwlock_t *rw) +{ + return rw->counter >= 0; +} + +/* + * write_can_lock - would write_trylock() succeed? + * @lock: the rwlock in question. + */ +static inline int __raw_write_can_lock(raw_rwlock_t *rw) +{ + return !rw->counter; +} + +#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) +#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) + +#define _raw_spin_relax(lock) cpu_relax() +#define _raw_read_relax(lock) cpu_relax() +#define _raw_write_relax(lock) cpu_relax() + +#endif /* _ASM_UBICOM32_SPINLOCK_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock_types.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock_types.h new file mode 100644 index 000000000..3745bca63 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock_types.h @@ -0,0 +1,43 @@ +/* + * arch/ubicom32/include/asm/spinlock_types.h + * Spinlock related structure definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SPINLOCK_TYPES_H +#define _ASM_UBICOM32_SPINLOCK_TYPES_H + +typedef struct { + volatile unsigned int lock; +} raw_spinlock_t; + +typedef struct { + raw_spinlock_t lock; + volatile int counter; +} raw_rwlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } +#define __RAW_RW_LOCK_UNLOCKED { __RAW_SPIN_LOCK_UNLOCKED, 0 } + +#endif /* _ASM_UBICOM32_SPINLOCK_TYPES_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/stacktrace.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/stacktrace.h new file mode 100644 index 000000000..f278ac7b5 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/stacktrace.h @@ -0,0 +1,72 @@ +/* + * arch/ubicom32/include/asm/stacktrace.h + * Stacktrace functions for the Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_STACKTRACE_H +#define _ASM_UBICOM32_STACKTRACE_H + +#define between(a, b, c) (( \ + ((unsigned long) a) >= ((unsigned long) b)) && \ + (((unsigned long)a) <= ((unsigned long)c))) + +/* + * These symbols are filled in by the linker. + */ +extern unsigned long _stext; +extern unsigned long _etext; + +/* OCM text goes from __ocm_text_run_begin to __data_begin */ +extern unsigned long __ocm_text_run_begin; +extern unsigned long __data_begin; + +/* Account for OCM case - see stacktrace.c maybe combine(also trap.c) */ +/* + * ubicom32_is_kernel() + * + * Check to see if the given address belongs to the kernel. + * NOMMU does not permit any other means. + */ +static inline int ubicom32_is_kernel(unsigned long addr) +{ + int is_kernel = between(addr, &_stext, &_etext) || \ + between(addr, &__ocm_text_run_begin, &__data_begin); + +#ifdef CONFIG_MODULES + if (!is_kernel) + is_kernel = is_module_address(addr); +#endif + return is_kernel; +} + +extern unsigned long stacktrace_iterate( + unsigned long **trace, + unsigned long stext, unsigned long etext, + unsigned long ocm_stext, unsigned long ocm_etext, + unsigned long sstack, unsigned long estack); +#ifdef CONFIG_STACKTRACE +void stacktrace_save_entries(struct task_struct *tsk, struct stack_trace *trace, unsigned long sp); +#endif +#endif /* _ASM_UBICOM32_STACKTRACE_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/stat.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/stat.h new file mode 100644 index 000000000..e333c60e6 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/stat.h @@ -0,0 +1,104 @@ +/* + * arch/ubicom32/include/asm/stat.h + * File status definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_STAT_H +#define _ASM_UBICOM32_STAT_H + +struct __old_kernel_stat { + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; +}; + +struct stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long __unused1; + unsigned long st_mtime; + unsigned long __unused2; + unsigned long st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct stat64 { + unsigned long long st_dev; + unsigned char __pad1[2]; + +#define STAT64_HAS_BROKEN_ST_INO 1 + unsigned long __st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned long long st_rdev; + unsigned char __pad3[2]; + + long long st_size; + unsigned long st_blksize; + + unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ + + unsigned long st_atime; + unsigned long st_atime_nsec; + + unsigned long st_mtime; + unsigned long st_mtime_nsec; + + unsigned long st_ctime; + unsigned long st_ctime_nsec; + + unsigned long long st_ino; +}; + +#endif /* _ASM_UBICOM32_STAT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/statfs.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/statfs.h new file mode 100644 index 000000000..15890d436 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/statfs.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/statfs.h + * Generic statfs.h definitions + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_STATFS_H +#define _ASM_UBICOM32_STATFS_H + +#include + +#endif /* _ASM_UBICOM32_STATFS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/string.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/string.h new file mode 100644 index 000000000..7f24bf593 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/string.h @@ -0,0 +1,40 @@ +/* + * arch/ubicom32/include/asm/string.h + * String operation definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_STRING_H +#define _ASM_UBICOM32_STRING_H + +#define __HAVE_ARCH_MEMSET +extern void *memset(void *b, int c, size_t len); + +#define __HAVE_ARCH_MEMCPY +extern void *memcpy(void *to, const void *from, size_t len); + +#define __HAVE_ARCH_MEMMOVE +extern void * memmove(void *to, const void *from, size_t len); + +#endif /* _ASM_UBICOM32_STRING_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/swab.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/swab.h new file mode 100644 index 000000000..180a50311 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/swab.h @@ -0,0 +1,45 @@ +/* + * arch/ubicom32/include/asm/byteorder.h + * Byte order swapping utility routines. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_BYTEORDER_H +#define _ASM_UBICOM32_BYTEORDER_H + +#include + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#if defined(IP7000) || defined(IP7000_REV2) + +#define __arch__swab16 __builtin_ubicom32_swapb_2 +#define __arch__swab32 __builtin_ubicom32_swapb_4 + +#endif /* IP7000 */ + +#endif /* _ASM_UBICOM32_BYTEORDER_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/switch-dev.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/switch-dev.h new file mode 100644 index 000000000..ed67e94aa --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/switch-dev.h @@ -0,0 +1,51 @@ +/* + * arch/ubicom32/include/asm/switch-dev.h + * generic Ethernet switch platform data definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SWITCH_DEV_H +#define _ASM_UBICOM32_SWITCH_DEV_H + +#define SWITCH_DEV_FLAG_HW_RESET 0x01 +#define SWITCH_DEV_FLAG_SW_RESET 0x02 + +struct switch_core_platform_data { + /* + * See flags above + */ + u32_t flags; + + /* + * GPIO to use for nReset + */ + int pin_reset; + + /* + * Name of this switch + */ + const char *name; +}; + +#endif /* _ASM_UBICOM32_SWITCH_DEV_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/system.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/system.h new file mode 100644 index 000000000..c3ec6083e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/system.h @@ -0,0 +1,101 @@ +/* + * arch/ubicom32/include/asm/system.h + * Low level switching definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_SYSTEM_H +#define _ASM_UBICOM32_SYSTEM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * switch_to(n) should switch tasks to task ptr, first checking that + * ptr isn't the current task, in which case it does nothing. + */ +asmlinkage void resume(void); +extern void *__switch_to(struct task_struct *prev, + struct thread_struct *prev_switch, + struct thread_struct *next_switch); + +/* + * We will need a per linux thread sw_ksp for the switch_to macro to + * track the kernel stack pointer for the current thread on that linux thread. + */ +#define switch_to(prev,next,last) \ +({ \ + void *_last; \ + _last = (void *) \ + __switch_to(prev, &prev->thread, &next->thread); \ + (last) = _last; \ +}) + +/* + * Force strict CPU ordering. + * Not really required on ubicom32... + */ +#define nop() asm volatile ("nop"::) +#define mb() asm volatile ("" : : :"memory") +#define rmb() asm volatile ("" : : :"memory") +#define wmb() asm volatile ("" : : :"memory") +#define set_mb(var, value) ({ (var) = (value); wmb(); }) + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#define smp_read_barrier_depends() read_barrier_depends() +#else +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#define smp_read_barrier_depends() do { } while(0) +#endif + +#define read_barrier_depends() ((void)0) + +/* + * The following defines change how the scheduler calls the switch_to() + * macro. + * + * 1) The first causes the runqueue to be unlocked on entry to + * switch_to(). Since our ctx code does not play with the runqueue + * we do not need it unlocked. + * + * 2) The later turns interrupts on during a ctxsw to reduce the latency of + * interrupts during ctx. At this point in the port, we believe that this + * latency is not a problem since we have very little code to perform a ctxsw. + */ +// #define __ARCH_WANT_UNLOCKED_CTXSW +// #define __ARCH_WANT_INTERRUPTS_ON_CTXSW + +#endif /* _ASM_UBICOM32_SYSTEM_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/termbits.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/termbits.h new file mode 100644 index 000000000..a7b3381f8 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/termbits.h @@ -0,0 +1,227 @@ +/* + * arch/ubicom32/include/asm/termbits.h + * Terminal/serial port definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_TERMBITS_H +#define _ASM_UBICOM32_TERMBITS_H + +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +struct termios2 { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +struct ktermios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag bit meaning */ +#define CBAUD 0010017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define BOTHER 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 +#define CIBAUD 002003600000 /* input baud rate */ +#define CMSPAR 010000000000 /* mark or space (stick) parity */ +#define CRTSCTS 020000000000 /* flow control */ + +#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#endif /* _ASM_UBICOM32_TERMBITS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/termios.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/termios.h new file mode 100644 index 000000000..5c16fe7e9 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/termios.h @@ -0,0 +1,119 @@ +/* + * arch/ubicom32/include/asm/termios.h + * Ubicom32 termio definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_TERMIOS_H +#define _ASM_UBICOM32_TERMIOS_H + +#include +#include + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#ifdef __KERNEL__ +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" +#endif + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + +#ifdef __KERNEL__ + +/* + * Translate a "termio" structure into a "termios". Ugh. + */ +#define user_termio_to_kernel_termios(termios, termio) \ +({ \ + unsigned short tmp; \ + get_user(tmp, &(termio)->c_iflag); \ + (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ + get_user(tmp, &(termio)->c_oflag); \ + (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \ + get_user(tmp, &(termio)->c_cflag); \ + (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \ + get_user(tmp, &(termio)->c_lflag); \ + (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ + get_user((termios)->c_line, &(termio)->c_line); \ + copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ +}) + +/* + * Translate a "termios" structure into a "termio". Ugh. + */ +#define kernel_termios_to_user_termio(termio, termios) \ +({ \ + put_user((termios)->c_iflag, &(termio)->c_iflag); \ + put_user((termios)->c_oflag, &(termio)->c_oflag); \ + put_user((termios)->c_cflag, &(termio)->c_cflag); \ + put_user((termios)->c_lflag, &(termio)->c_lflag); \ + put_user((termios)->c_line, &(termio)->c_line); \ + copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ +}) + +#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2)) +#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2)) +#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) +#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) + +#endif /* __KERNEL__ */ + +#endif /* _ASM_UBICOM32_TERMIOS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread-asm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread-asm.h new file mode 100644 index 000000000..f9566037e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread-asm.h @@ -0,0 +1,51 @@ +/* + * arch/ubicom32/include/asm/thread-asm.h + * Ubicom32 architecture specific thread definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_THREAD_ASM_H +#define _ASM_UBICOM32_THREAD_ASM_H + +/* + * thread_get_self + * Read and shift the current thread into reg + * + * Note that we don't need to mask the result as bits 6 through 31 of the + * ROSR are zeroes. + */ +.macro thread_get_self reg + lsr.4 \reg, ROSR, #2 +.endm + +/* + * thread_get_self_mask + * Read and shift the current thread mask into reg + */ +.macro thread_get_self_mask reg + lsr.4 \reg, ROSR, #2 + lsl.4 \reg, #1, \reg /* Thread bit */ +.endm + +#endif /* _ASM_UBICOM32_THREAD_ASM_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread.h new file mode 100644 index 000000000..69c925ea4 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread.h @@ -0,0 +1,320 @@ +/* + * arch/ubicom32/include/asm/thread.h + * Ubicom32 architecture specific thread definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_THREAD_H +#define _ASM_UBICOM32_THREAD_H + +#if !defined(__ASSEMBLY__) + +#include +#include + +typedef int thread_t; +typedef unsigned char thread_type_t; +typedef void (*thread_exec_fn_t)(void *arg); + +#define THREAD_NULL 0x40 +#define THREAD_TYPE_HRT (1 << 0) +#define THREAD_TYPE_SPECIAL 0 +#define THREAD_TYPE_NORMAL 0 +#define THREAD_TYPE_BACKGROUND (1 << 1) + +/* + * This is the upper bound on the maximum hardware threads that one will find + * on a Ubicom processor. It is used to size per hardware thread data structures. + */ +#define THREAD_ARCHITECTURAL_MAX 16 + +/* + * TODO: Rename this at some point to be thread_ + */ +extern unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX]; + + +/* + * thread_get_self() + */ +static inline thread_t thread_get_self(void) +{ + thread_t result; + + /* + * Note that ROSR has zeroes in bits 6 through 31 and so we don't need + * to do any additional bit masking here. + */ + asm ( + "lsr.4 %0, ROSR, #2 \n\t" + : "=d" (result) + : + : "cc" + ); + + return result; +} + +/* + * thread_suspend() + */ +static inline void thread_suspend(void) +{ + asm volatile ( + "suspend\n\t" + : + : + ); +} + +/* + * thread_resume() + */ +static inline void thread_resume(thread_t thread) +{ + asm volatile ( + "move.4 MT_ACTIVE_SET, %0 \n\t" + "pipe_flush 0 \n\t" + "pipe_flush 0 \n\t" + : + : "d" (1 << thread) + ); +} + + + +/* + * thread_enable_mask() + * Enable all threads in the mask. + * + * All writes to MT_EN must be protected by the MT_EN_LOCK bit + */ +static inline void thread_enable_mask(unsigned int mask) +{ + /* + * must flush the pipeline twice. + * first pipe_flush is to ensure write to MT_EN is completed + * second one is to ensure any new instructions from + * the targeted thread (the one being disabled), that + * are issued while the write to MT_EN is being executed, + * are completed. + */ + UBICOM32_LOCK(MT_EN_LOCK_BIT); + asm volatile ( + "or.4 MT_EN, MT_EN, %0 \n\t" + "pipe_flush 0 \n\t" + "pipe_flush 0 \n\t" + : + : "d" (mask) + : "cc" + ); + UBICOM32_UNLOCK(MT_EN_LOCK_BIT); +} + +/* + * thread_enable() + */ +static inline void thread_enable(thread_t thread) +{ + thread_enable_mask(1 << thread); +} + +/* + * thread_disable_mask() + * Disable all threads in the mask. + * + * All writes to MT_EN must be protected by the MT_EN_LOCK bit + */ +static inline void thread_disable_mask(unsigned int mask) +{ + /* + * must flush the pipeline twice. + * first pipe_flush is to ensure write to MT_EN is completed + * second one is to ensure any new instructions from + * the targeted thread (the one being disabled), that + * are issued while the write to MT_EN is being executed, + * are completed. + */ + UBICOM32_LOCK(MT_EN_LOCK_BIT); + asm volatile ( + "and.4 MT_EN, MT_EN, %0 \n\t" + "pipe_flush 0 \n\t" + "pipe_flush 0 \n\t" + : + : "d" (~mask) + : "cc" + ); + UBICOM32_UNLOCK(MT_EN_LOCK_BIT); +} + +/* + * thread_disable() + */ +static inline void thread_disable(thread_t thread) +{ + thread_disable_mask(1 << thread); +} + +/* + * thread_disable_others() + * Disable all other threads + */ +static inline void thread_disable_others(void) +{ + thread_t self = thread_get_self(); + thread_disable_mask(~(1 << self)); +} + +/* + * thread_is_trapped() + * Is the specified tid trapped? + */ +static inline int thread_is_trapped(thread_t tid) +{ + int thread_mask = (1 << tid); + int trap_thread; + + asm ( + "move.4 %0, MT_TRAP \n\t" + : "=d" (trap_thread) + : + ); + return (trap_thread & thread_mask); +} + +/* + * thread_is_enabled() + * Is the specified tid enabled? + */ +static inline int thread_is_enabled(thread_t tid) +{ + int thread_mask = (1 << tid); + int enabled_threads; + + asm ( + "move.4 %0, MT_EN \n\t" + : "=d" (enabled_threads) + : + ); + return (enabled_threads & thread_mask); +} + +/* + * thread_get_instruction_count() + */ +static inline unsigned int thread_get_instruction_count(void) +{ + unsigned int result; + asm ( + "move.4 %0, INST_CNT \n\t" + : "=r" (result) + ); + return result; +} + +/* + * thread_get_pc() + * pc could point to a speculative and cancelled instruction unless thread is disabled + */ +static inline void *thread_get_pc(thread_t thread) +{ + void *result; + asm ( + "move.4 csr, %1 \n\t" + "setcsr_flush 0 \n\t" + "move.4 %0, pc \n\t" + "move.4 csr, #0 \n\t" + "setcsr_flush 0 \n\t" + : "=r" (result) + : "r" ((thread << 9) | (1 << 8)) + ); + return result; +} + +/* + * thread_get_trap_cause() + * This should be called only when the thread is not running + */ +static inline unsigned int thread_get_trap_cause(thread_t thread) +{ + unsigned int result; + asm ( + "move.4 csr, %1 \n\t" + "setcsr_flush 0 \n\t" + "move.4 %0, trap_cause \n\t" + "move.4 csr, #0 \n\t" + "setcsr_flush 0 \n\t" + : "=r" (result) + : "r" ((thread << 9) | (1 << 8)) + ); + return result; +} + +/* + * THREAD_STALL macro. + */ +#define THREAD_STALL \ + asm volatile ( \ + "move.4 mt_dbg_active_clr, #-1 \n\t" \ + "pipe_flush 0 \n\t" \ + : \ + : \ + ) + +extern unsigned int thread_get_mainline(void); +extern void thread_set_mainline(thread_t tid); +extern thread_t thread_alloc(void); +extern thread_t thread_start(thread_t thread, thread_exec_fn_t exec, void *arg, unsigned int *sp_high, thread_type_t type); + +/* + * asm macros + */ +asm ( +/* + * thread_get_self + * Read and shift the current thread into reg + * + * Note that we don't need to mask the result as bits 6 through 31 of the + * ROSR are zeroes. + */ +".macro thread_get_self reg \n\t" +" lsr.4 \\reg, ROSR, #2 \n\t" +".endm \n\t" + +/* + * thread_get_self_mask + * Read and shift the current thread mask into reg + */ +".macro thread_get_self_mask reg \n\t" +" lsr.4 \\reg, ROSR, #2 \n\t" +" lsl.4 \\reg, #1, \\reg \n\t" /* Thread bit */ +".endm \n\t" +); + +#else /* __ASSEMBLY__ */ + +#include + +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_UBICOM32_THREAD_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread_info.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread_info.h new file mode 100644 index 000000000..55c69dadd --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread_info.h @@ -0,0 +1,134 @@ +/* + * arch/ubicom32/include/asm/thread_info.h + * Ubicom32 architecture low-level thread information. + * + * (C) Copyright 2009, Ubicom, Inc. + * Adapted from the i386 and PPC versions by Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2002 David Howells (dhowells@redhat.com) + * - Incorporating suggestions made by Linus Torvalds and Dave Miller + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_THREAD_INFO_H +#define _ASM_UBICOM32_THREAD_INFO_H + +#include + +/* + * Size of kernel stack for each process. This must be a power of 2... + */ +#ifdef CONFIG_4KSTACKS +#define THREAD_SIZE_ORDER (0) +#else +#define THREAD_SIZE_ORDER (1) +#endif + +/* + * for asm files, THREAD_SIZE is now generated by asm-offsets.c + */ +#define THREAD_SIZE (PAGE_SIZE< preemptable, <0 => BUG */ + int interrupt_nesting; /* Interrupt nesting level. */ + struct restart_block restart_block; +}; + +/* + * macros/functions for gaining access to the thread information structure + */ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .interrupt_nesting = 0, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; + + asm ( + "and.4 %0, sp, %1\n\t" + : "=&r" (ti) + : "d" (~(THREAD_SIZE-1)) + : "cc" + ); + + return ti; +} + +#define STACK_WARN (THREAD_SIZE / 8) + +#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR 1 + +/* thread information allocation */ +#define alloc_thread_info(tsk) ((struct thread_info *) \ + __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER)) +#define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_SIZE_ORDER) +#endif /* __ASSEMBLY__ */ + +#define PREEMPT_ACTIVE 0x4000000 + +/* + * thread information flag bit numbers + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_SIGPENDING 1 /* signal pending */ +#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ +#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling + TIF_NEED_RESCHED */ +#define TIF_MEMDIE 4 + +/* as above, but as bit values */ +#define _TIF_SYSCALL_TRACE (1<. + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_TIMEX_H +#define _ASM_UBICOM32_TIMEX_H + +#define CLOCK_TICK_RATE 266000000 + +// #define ARCH_HAS_READ_CURRENT_TIMER + +typedef unsigned long cycles_t; + +static inline cycles_t get_cycles(void) +{ + return 0; +} + +extern int timer_alloc(void); +extern void timer_set(int timervector, unsigned int cycles); +extern int timer_reset(int timervector, unsigned int cycles); +extern void timer_tick_init(void); +extern void timer_device_init(void); + +#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) +extern void local_timer_interrupt(void); +#endif + +#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) +extern int local_timer_setup(unsigned int cpu); +#endif + +#endif /* _ASM_UBICOM32_TIMEX_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlb.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlb.h new file mode 100644 index 000000000..cd45996d5 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlb.h @@ -0,0 +1,47 @@ +/* + * arch/ubicom32/include/asm/tlb.h + * Ubicom32 architecture TLB operations. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_TLB_H +#define _ASM_UBICOM32_TLB_H + +/* + * ubicom32 doesn't need any special per-pte or + * per-vma handling.. + */ +#define tlb_start_vma(tlb, vma) do { } while (0) +#define tlb_end_vma(tlb, vma) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) + +/* + * .. because we flush the whole mm when it + * fills up. + */ +#define tlb_flush(tlb) + +#include + +#endif /* _ASM_UBICOM32_TLB_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlbflush.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlbflush.h new file mode 100644 index 000000000..0317aca8d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlbflush.h @@ -0,0 +1,79 @@ +/* + * arch/ubicom32/include/asm/tlbflush.h + * TLB operations for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2000 Lineo, David McCullough + * Copyright (C) 2000-2002, Greg Ungerer + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_TLB_FLUSH_H +#define _ASM_UBICOM32_TLB_FLUSH_H + +#include + +/* + * flush all user-space atc entries. + */ +static inline void __flush_tlb(void) +{ + BUG(); +} + +static inline void __flush_tlb_one(unsigned long addr) +{ + BUG(); +} + +#define flush_tlb() __flush_tlb() + +/* + * flush all atc entries (both kernel and user-space entries). + */ +static inline void flush_tlb_all(void) +{ + BUG(); +} + +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + BUG(); +} + +static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) +{ + BUG(); +} + +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + BUG(); +} + +static inline void flush_tlb_kernel_page(unsigned long addr) +{ + BUG(); +} + +#endif /* _ASM_UBICOM32_TLB_FLUSH_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/topology.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/topology.h new file mode 100644 index 000000000..b4de1437d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/topology.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/topology.h + * Generic topology.h definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_TOPOLOGY_H +#define _ASM_UBICOM32_TOPOLOGY_H + +#include + +#endif /* _ASM_UBICOM32_TOPOLOGY_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/traps.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/traps.h new file mode 100644 index 000000000..9edcca9b5 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/traps.h @@ -0,0 +1,55 @@ +/* + * arch/ubicom32/include/asm/traps.h + * Trap related definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_TRAPS_H +#define _ASM_UBICOM32_TRAPS_H + +/* + * Trap causes passed from ultra to Host OS + */ +#define TRAP_CAUSE_TOTAL 13 +#define TRAP_CAUSE_DST_RANGE_ERR 12 +#define TRAP_CAUSE_SRC1_RANGE_ERR 11 +#define TRAP_CAUSE_I_RANGE_ERR 10 +#define TRAP_CAUSE_DCAPT 9 +#define TRAP_CAUSE_DST_SERROR 8 +#define TRAP_CAUSE_SRC1_SERROR 7 +#define TRAP_CAUSE_DST_MISALIGNED 6 +#define TRAP_CAUSE_SRC1_MISALIGNED 5 +#define TRAP_CAUSE_DST_DECODE_ERR 4 +#define TRAP_CAUSE_SRC1_DECODE_ERR 3 +#define TRAP_CAUSE_ILLEGAL_INST 2 +#define TRAP_CAUSE_I_SERROR 1 +#define TRAP_CAUSE_I_DECODE_ERR 0 + +extern void trap_handler(int irq, struct pt_regs *regs); +extern void trap_init_interrupt(void); +extern void unaligned_emulate(unsigned int thread); +extern int unaligned_only(unsigned int cause); + +#endif /* _ASM_UBICOM32_TRAPS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/types.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/types.h new file mode 100644 index 000000000..5b960dda3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/types.h @@ -0,0 +1,75 @@ +/* + * arch/ubicom32/include/asm/types.h + * Date type definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_TYPES_H +#define _ASM_UBICOM32_TYPES_H + +/* + * This file is never included by application software unless + * explicitly requested (e.g., via linux/types.h) in which case the + * application is Linux specific so (user-) name space pollution is + * not a major issue. However, for interoperability, libraries still + * need to be careful to avoid a name clashes. + */ + +#include + +#ifndef __ASSEMBLY__ + +typedef unsigned short umode_t; + +#endif /* __ASSEMBLY__ */ + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +#define BITS_PER_LONG 32 + +#ifndef __ASSEMBLY__ + +/* DMA addresses are always 32-bits wide */ + +typedef u32 dma_addr_t; +typedef u32 dma64_addr_t; + +/* + * XXX These are "Ubicom style" typedefs. They should be removed in all files used by linux. + */ +typedef u32 u32_t; +typedef s32 s32_t; +typedef u16 u16_t; +typedef s16 s16_t; +typedef u8 u8_t; +typedef s8 s8_t; + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* _ASM_UBICOM32_TYPES_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/uaccess.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/uaccess.h new file mode 100644 index 000000000..eef739d12 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/uaccess.h @@ -0,0 +1,347 @@ +/* + * arch/ubicom32/include/asm/uaccess.h + * User space memory access functions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * arch/alpha + */ +#ifndef _ASM_UBICOM32_UACCESS_H +#define _ASM_UBICOM32_UACCESS_H + +/* + * User space memory access functions + */ +#include +#include +#include + +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +/* + * Ubicom32 does not currently support the exception table handling. + */ +extern unsigned long search_exception_table(unsigned long); + + +#if defined(CONFIG_ACCESS_OK_CHECKS_ENABLED) +extern int __access_ok(unsigned long addr, unsigned long size); +#else +static inline int __access_ok(unsigned long addr, unsigned long size) +{ + return 1; +} +#endif +#define access_ok(type, addr, size) \ + likely(__access_ok((unsigned long)(addr), (size))) + +/* + * The following functions do not exist. They keep callers + * of put_user and get_user from passing unsupported argument + * types. They result in a link time error. + */ +extern int __put_user_bad(void); +extern int __get_user_bad(void); + +/* + * __put_user_no_check() + * Put the requested data into the user space verifying the address + * + * Careful to not + * (a) re-use the arguments for side effects (sizeof/typeof is ok) + * (b) require any knowledge of processes at this stage + */ +#define __put_user_no_check(x, ptr, size) \ +({ \ + int __pu_err = 0; \ + __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ + switch (size) { \ + case 1: \ + case 2: \ + case 4: \ + case 8: \ + *__pu_addr = (__typeof__(*(ptr)))x; \ + break; \ + default: \ + __pu_err = __put_user_bad(); \ + break; \ + } \ + __pu_err; \ +}) + +/* + * __put_user_check() + * Put the requested data into the user space verifying the address + * + * Careful to not + * (a) re-use the arguments for side effects (sizeof/typeof is ok) + * (b) require any knowledge of processes at this stage + * + * If requested, access_ok() will verify that ptr is a valid user + * pointer. + */ +#define __put_user_check(x, ptr, size) \ +({ \ + int __pu_err = -EFAULT; \ + __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ + if (access_ok(VERIFY_WRITE, __pu_addr, size)) { \ + __pu_err = 0; \ + switch (size) { \ + case 1: \ + case 2: \ + case 4: \ + case 8: \ + *__pu_addr = (__typeof__(*(ptr)))x; \ + break; \ + default: \ + __pu_err = __put_user_bad(); \ + break; \ + } \ + } \ + __pu_err; \ +}) + +/* + * __get_user_no_check() + * Read the value at ptr into x. + * + * If requested, access_ok() will verify that ptr is a valid user + * pointer. If the caller passes a modifying argument for ptr (e.g. x++) + * this macro will not work. + */ +#define __get_user_no_check(x, ptr, size) \ +({ \ + int __gu_err = 0; \ + __typeof__((x)) __gu_val = 0; \ + const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ + switch (size) { \ + case 1: \ + case 2: \ + case 4: \ + case 8: \ + __gu_val = (__typeof__((x)))*(__gu_addr); \ + break; \ + default: \ + __gu_err = __get_user_bad(); \ + (x) = 0; \ + break; \ + } \ + (x) = __gu_val; \ + __gu_err; \ +}) + +/* + * __get_user_check() + * Read the value at ptr into x. + * + * If requested, access_ok() will verify that ptr is a valid user + * pointer. + */ +#define __get_user_check(x, ptr, size) \ +({ \ + int __gu_err = -EFAULT; \ + __typeof__(x) __gu_val = 0; \ + const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ + if (access_ok(VERIFY_READ, __gu_addr, size)) { \ + __gu_err = 0; \ + switch (size) { \ + case 1: \ + case 2: \ + case 4: \ + case 8: \ + __gu_val = (__typeof__((x)))*(__gu_addr); \ + break; \ + default: \ + __gu_err = __get_user_bad(); \ + (x) = 0; \ + break; \ + } \ + } \ + (x) = __gu_val; \ + __gu_err; \ +}) + +/* + * The "xxx" versions are allowed to perform some amount of address + * space checking. See access_ok(). + */ +#define put_user(x,ptr) \ + __put_user_check((__typeof__(*(ptr)))(x),(ptr), sizeof(*(ptr))) +#define get_user(x,ptr) \ + __get_user_check((x), (ptr), sizeof(*(ptr))) + +/* + * The "__xxx" versions do not do address space checking, useful when + * doing multiple accesses to the same area (the programmer has to do the + * checks by hand with "access_ok()") + */ +#define __put_user(x,ptr) \ + __put_user_no_check((__typeof__(*(ptr)))(x),(ptr), sizeof(*(ptr))) +#define __get_user(x,ptr) \ + __get_user_no_check((x), (ptr), sizeof(*(ptr))) + +/* + * __copy_tofrom_user_no_check() + * Copy the data either to or from user space. + * + * Return the number of bytes NOT copied. + */ +static inline unsigned long +__copy_tofrom_user_no_check(void *to, const void *from, unsigned long n) +{ + memcpy(to, from, n); + return 0; +} + +/* + * copy_to_user() + * Copy the kernel data to user space. + * + * Return the number of bytes that were copied. + */ +static inline unsigned long +copy_to_user(void __user *to, const void *from, unsigned long n) +{ + if (!access_ok(VERIFY_WRITE, to, n)) { + return n; + } + return __copy_tofrom_user_no_check((__force void *)to, from, n); +} + +/* + * copy_from_user() + * Copy the user data to kernel space. + * + * Return the number of bytes that were copied. On error, we zero + * out the destination. + */ +static inline unsigned long +copy_from_user(void *to, const void __user *from, unsigned long n) +{ + if (!access_ok(VERIFY_READ, from, n)) { + return n; + } + return __copy_tofrom_user_no_check(to, (__force void *)from, n); +} + +#define __copy_to_user(to, from, n) \ + __copy_tofrom_user_no_check((__force void *)to, from, n) +#define __copy_from_user(to, from, n) \ + __copy_tofrom_user_no_check(to, (__force void *)from, n) +#define __copy_to_user_inatomic(to, from, n) \ + __copy_tofrom_user_no_check((__force void *)to, from, n) +#define __copy_from_user_inatomic(to, from, n) \ + __copy_tofrom_user_no_check(to, (__force void *)from, n) + +#define copy_to_user_ret(to, from, n, retval) \ + ({ if (copy_to_user(to, from, n)) return retval; }) + +#define copy_from_user_ret(to, from, n, retval) \ + ({ if (copy_from_user(to, from, n)) return retval; }) + +/* + * strncpy_from_user() + * Copy a null terminated string from userspace. + * + * dst - Destination in kernel space. The buffer must be at least count. + * src - Address of string in user space. + * count - Maximum number of bytes to copy (including the trailing NULL). + * + * Returns the length of the string (not including the trailing NULL. If + * count is smaller than the length of the string, we copy count bytes + * and return count. + * + */ +static inline long strncpy_from_user(char *dst, const __user char *src, long count) +{ + char *tmp; + if (!access_ok(VERIFY_READ, src, 1)) { + return -EFAULT; + } + + strncpy(dst, src, count); + for (tmp = dst; *tmp && count > 0; tmp++, count--) { + ; + } + return(tmp - dst); +} + +/* + * strnlen_user() + * Return the size of a string (including the ending 0) + * + * Return -EFAULT on exception, a value greater than if too long + */ +static inline long strnlen_user(const __user char *src, long n) +{ + if (!access_ok(VERIFY_READ, src, 1)) { + return -EFAULT; + } + return(strlen(src) + 1); +} + +#define strlen_user(str) strnlen_user(str, 32767) + +/* + * __clear_user() + * Zero Userspace + */ +static inline unsigned long __clear_user(__user void *to, unsigned long n) +{ + memset(to, 0, n); + return 0; +} + +/* + * clear_user() + * Zero user space (check for valid addresses) + */ +static inline unsigned long clear_user(__user void *to, unsigned long n) +{ + if (!access_ok(VERIFY_WRITE, to, n)) { + return -EFAULT; + } + return __clear_user(to, n); +} + +#endif /* _ASM_UBICOM32_UACCESS_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/uart_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/uart_tio.h new file mode 100644 index 000000000..19ef82efa --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/uart_tio.h @@ -0,0 +1,126 @@ +/* + * arch/ubicom32/include/asm/uart_tio.h + * Ubicom32 architecture UART TIO definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#ifndef _ASM_UBICOM32_UART_TIO_H +#define _ASM_UBICOM32_UART_TIO_H + +#include + +#define UARTTIO_RX_FIFO_SIZE 16 +#define UARTTIO_TX_FIFO_SIZE 16 + +/* + * Interrupt flags + */ +#define UARTTIO_UART_INT_RX 0x00000001 // set when a character has been recevied (TODO: add watermark) +#define UARTTIO_UART_INT_RXOVF 0x00000002 // set when the receive buffer has overflowed +#define UARTTIO_UART_INT_RXFRAME 0x00000004 // set when there has been a framing error + +#define UARTTIO_UART_INT_TX 0x00000100 // set every time a character is transmitted +#define UARTTIO_UART_INT_TXBE 0x00000200 // set when the transmit buffer is empty (TODO: add watermark) + +#define UARTTIO_UART_FLAG_ENABLED 0x80000000 +#define UARTTIO_UART_FLAG_SET_RATE 0x00000001 // set to update baud rate +#define UARTTIO_UART_FLAG_RESET 0x00000002 // set to reset the port +struct uarttio_uart { + volatile u32_t flags; + + volatile u32_t baud_rate; + volatile u32_t current_baud_rate; + u32_t bit_time; + + /* + * Modem status register + */ + volatile u32_t status; + + /* + * Interrupt registers + */ + volatile u32_t int_mask; + volatile u32_t int_flags; + + /* + * Ports and pins + */ + u32_t rx_port; + u32_t tx_port; + + u8_t rx_pin; + u8_t tx_pin; + + /* + * Configuration Data + */ + u8_t rx_bits; + u8_t rx_stop_bits; + u8_t tx_bits; + u8_t tx_stop_bits; + + /* + * RX state machine data + */ + u32_t rx_timer; + u32_t rx_bit_pos; + u32_t rx_byte; + u32_t rx_fifo_head; + u32_t rx_fifo_tail; + u32_t rx_fifo_size; + + /* + * TX state machine data + */ + u32_t tx_timer; + u32_t tx_bit_pos; + u32_t tx_byte; + u32_t tx_fifo_head; + u32_t tx_fifo_tail; + u32_t tx_fifo_size; + + /* + * FIFOs + */ + u8_t rx_fifo[UARTTIO_RX_FIFO_SIZE]; + u8_t tx_fifo[UARTTIO_TX_FIFO_SIZE]; +}; + +#define UARTTIO_VP_VERSION 1 +struct uarttio_regs { + u32_t version; + + u32_t thread; + + u32_t max_uarts; + + struct uarttio_uart uarts[0]; +}; + +#define UARTTIO_NODE_VERSION 1 +struct uarttio_node { + struct devtree_node dn; + + u32_t version; + struct uarttio_regs *regs; + u32_t regs_sz; +}; + +#endif /* _ASM_UBICOM32_UART_TIO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-cs4384.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-cs4384.h new file mode 100644 index 000000000..18e7634ff --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-cs4384.h @@ -0,0 +1,52 @@ +/* + * arch/ubicom32/include/asm/ubi32-cs4384.h + * Ubicom32 architecture CS4384 driver platform data definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#ifndef _ASM_UBICOM32_UBI32_CS4384_H +#define _ASM_UBICOM32_UBI32_CS4384_H + +enum ubi32_cs4384_mclk_source { + UBI32_CS4384_MCLK_PWM_0, + UBI32_CS4384_MCLK_PWM_1, + UBI32_CS4384_MCLK_PWM_2, + UBI32_CS4384_MCLK_CLKDIV_1, + UBI32_CS4384_MCLK_OTHER, +}; + +struct ubi32_cs4384_mclk_entry { + /* + * Rate, in Hz, of this entry + */ + int rate; + + /* + * The divider to program to get the rate + */ + int div; +}; + +struct ubi32_cs4384_platform_data { + enum ubi32_cs4384_mclk_source mclk_src; + + int n_mclk; + struct ubi32_cs4384_mclk_entry *mclk_entries; +}; +#endif /* _ASM_UBICOM32_UBI32_CS4384_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-pcm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-pcm.h new file mode 100644 index 000000000..ab14b3681 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-pcm.h @@ -0,0 +1,54 @@ +/* + * arch/ubicom32/include/asm/ubi32-pcm.h + * Ubicom32 architecture PCM driver platform data definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#ifndef _ASM_UBICOM32_UBI32_PCM_H +#define _ASM_UBICOM32_UBI32_PCM_H + +/* + * This function is called when the sample rate has changed + */ +typedef int (*ubi32_pcm_set_rate_fn_t)(void *appdata, int rate); + +struct ubi32pcm_platform_data { + /* + * Name of the audio node/inst + */ + const char *node_name; + const char *inst_name; + int inst_num; + + /* + * Application specific data provided when calling functions + */ + void *appdata; + + /* + * Functions called when various things happen + */ + ubi32_pcm_set_rate_fn_t set_rate; + + /* + * Pointer to optional upper layer data (i.e. DAC config, etc) + */ + void *priv_data; +}; +#endif /* _ASM_UBICOM32_UBI32_PCM_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common-asm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common-asm.h new file mode 100644 index 000000000..82696bbbf --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common-asm.h @@ -0,0 +1,49 @@ +/* + * arch/ubicom32/include/asm/ubicom32-common-asm.h + * Ubicom32 atomic lock operations. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_UBICOM32_COMMON_ASM_H +#define _ASM_UBICOM32_UBICOM32_COMMON_ASM_H + +/* + * atomic_lock_acquire macro + * Equivalent to __atomic_lock_acquire() + */ +.macro atomic_lock_acquire + bset scratchpad1, scratchpad1, #ATOMIC_LOCK_BIT + jmpne.f .-4 +.endm + +/* + * atomic_lock_release macro + * Equivalent to __atomic_lock_release() + */ +.macro atomic_lock_release + bclr scratchpad1, scratchpad1, #ATOMIC_LOCK_BIT +.endm + +#endif /* _ASM_UBICOM32_UBICOM32_COMMON_ASM_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common.h new file mode 100644 index 000000000..1f05a8cd3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common.h @@ -0,0 +1,128 @@ +/* + * arch/ubicom32/include/asm/ubicom32-common.h + * Ubicom32 atomic lock operations. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_UBICOM32_COMMON_H +#define _ASM_UBICOM32_UBICOM32_COMMON_H + +#define S(arg) #arg +#define D(arg) S(arg) +/* + * scratchpad1 is owned by the LDSR. + * + * The upper bits provide 16 global spinlocks. Acquiring one of these + * global spinlocks synchornizes across multiple threads and prevents + * the LDSR from delivering any interrupts while the lock is held. + * Use these locks only when absolutely required. + * + * The lower 16 bits of scratchpad1 are used as per thread interrupt + * enable/disable bits. These bits will prevent a thread from receiving + * any interrupts. + * + * Bit Usage: + * - MT_EN_LOCK_BIT - Protects writes to MT_EN, so code can read current value + * then write a new value atomically (profiler for example) + * - ATOMIC_LOCK_BIT - Used to provide general purpose atomic handling. + * - LDSR_LOCK_BIT - Used by the LDSR exclusively to provide protection. + * - DCCR_LOCK_BIT - Used to limit access to the DCCR cache control peripheral + * - ICCR_LOCK_BIT - Used to limit access to the ICCR cache control peripheral + * - LSB 16 bits - Used by the LDSR to represent thread enable/disable bits. + */ +#define MT_EN_LOCK_BIT 31 +#define ATOMIC_LOCK_BIT 30 +#define LDSR_LOCK_BIT 29 +#define PCI_LOCK_BIT 28 +#define ICCR_LOCK_BIT 27 +#define DCCR_LOCK_BIT 26 + +#if !defined(__ASSEMBLY__) + +#define UBICOM32_TRYLOCK(bit) \ + asm volatile ( \ + " move.4 %0, #0 \n\t" \ + " bset scratchpad1, scratchpad1, #"D(bit)" \n\t" \ + " jmpne.f 1f \n\t" \ + " move.4 %0, #1 \n\t" \ + "1: \n\t" \ + : "=r" (ret) \ + : \ + : "cc", "memory" \ + ) \ + +#define UBICOM32_UNLOCK(bit) \ + asm volatile ( \ + " bclr scratchpad1, scratchpad1, #"D(bit)" \n\t" \ + : \ + : \ + : "cc", "memory" \ + ) \ + +#define UBICOM32_LOCK(bit) \ + asm volatile ( \ + "1: bset scratchpad1, scratchpad1, #"D(bit)" \n\t" \ + " jmpne.f 1b \n\t" \ + : \ + : \ + : "cc", "memory" \ + ) \ + +/* + * __atomic_lock_trylock() + * Attempt to acquire the lock, return TRUE if acquired. + */ +static inline int __atomic_lock_trylock(void) +{ + int ret; + UBICOM32_TRYLOCK(ATOMIC_LOCK_BIT); + return ret; +} + +/* + * __atomic_lock_release() + * Release the global atomic lock. + * + * Note: no one is suspended waiting since this lock is a spinning lock. + */ +static inline void __atomic_lock_release(void) +{ + UBICOM32_UNLOCK(ATOMIC_LOCK_BIT); +} + +/* + * __atomic_lock_acquire() + * Acquire the global atomic lock, spin if not available. + */ +static inline void __atomic_lock_acquire(void) +{ + UBICOM32_LOCK(ATOMIC_LOCK_BIT); +} +#else /* __ASSEMBLY__ */ + +#include + +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_UBICOM32_UBICOM32_COMMON_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-spi-gpio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-spi-gpio.h new file mode 100644 index 000000000..b5379e3ef --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-spi-gpio.h @@ -0,0 +1,62 @@ +/* + * arch/ubicom32/include/asm/ubicom32-spi-gpio.h + * Platform driver data definitions for GPIO based SPI driver. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_UBICOM32_SPI_GPIO_H +#define _ASM_UBICOM32_UBICOM32_SPI_GPIO_H + +struct ubicom32_spi_gpio_platform_data { + /* + * GPIO to use for MOSI, MISO, CLK + */ + int pin_mosi; + int pin_miso; + int pin_clk; + + /* + * Default state of CLK line + */ + int clk_default; + + /* + * Number of chip selects on this bus + */ + int num_chipselect; + + /* + * The bus number of this chip + */ + int bus_num; +}; + +struct ubicom32_spi_gpio_controller_data { + /* + * GPIO to use for chip select + */ + int pin_cs; +}; + +#endif /* _ASM_UBICOM32_UBICOM32_SPI_GPIO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-tio.h new file mode 100644 index 000000000..4d87e5c0e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-tio.h @@ -0,0 +1,42 @@ +/* + * arch/ubicom32/include/asm/ubicom32-tio.h + * Threaded I/O interface definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_UBICOM32_TIO_H +#define _ASM_UBICOM32_UBICOM32_TIO_H + +extern u8_t usb_tio_read_u16(u32_t address, u16_t *data); +extern u8_t usb_tio_read_u8(u32_t address, u8_t *data); + +extern u8_t usb_tio_write_u16(u32_t address, u16_t data); +extern u8_t usb_tio_write_u8(u32_t address, u8_t data); + +extern u8_t usb_tio_read_fifo(u32_t address, u32_t buffer, u32_t bytes); +extern u8_t usb_tio_write_fifo(u32_t address, u32_t buffer, u32_t bytes); +extern u8_t usb_tio_write_fifo_sync(u32_t address, u32_t buffer, u32_t bytes); +extern void usb_tio_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx); + +#endif /* _ASM_UBICOM32_UBICOM32_TIO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32bl.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32bl.h new file mode 100644 index 000000000..498c75496 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32bl.h @@ -0,0 +1,84 @@ +/* + * arch/ubicom32/include/asm/ubicom32bl.h + * Ubicom32 architecture backlight driver platform data definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_UBICOM32_BL_H +#define _ASM_UBICOM32_UBICOM32_BL_H + +/* + * Different backlight control mechanisms + */ +enum ubicom32bl_pwm_types { + /* + * PWM controlled backlight + */ + UBICOM32BL_TYPE_PWM, + + /* + * HRT based PWM backlight + */ + UBICOM32BL_TYPE_PWM_HRT, + + /* + * No dimming, just on or off + */ + UBICOM32BL_TYPE_BINARY, +}; + +struct ubicom32bl_platform_data { + /* + * Default intensity of the backlight 0-255 + */ + u8_t default_intensity; + + /* + * TRUE if the backlight sense is active low. (inverted) + * FALSE if the backlight sense is active high. + */ + bool invert; + + /* + * Type of the backlight + */ + enum ubicom32bl_pwm_types type; + + /* + * GPIO of the backlight if UBICOM32BL_TYPE_PWM_HRT, UBICOM32BL_TYPE_BINARY + */ + unsigned gpio; + + /* + * PWM channel and parameters of the backlight if UBICOM32BL_TYPE_PWM + * pre_scaler: sets the rate at which the PWM timer is clocked. (clk_core / 2^pre_scaler) + * period: sets the period of the timer in timer cycles + * The duty cycle will be directly proportional to the brightness setting. + */ + u32_t pwm_channel; + u8_t pwm_prescale; + u16_t pwm_period; +}; + +#endif /* _ASM_UBICOM32_UBICOM32_BL_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32fb.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32fb.h new file mode 100644 index 000000000..ae994e261 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32fb.h @@ -0,0 +1,56 @@ +/* + * arch/ubicom32/include/asm/ubicom32fb.h + * Ubicom32 architecture video frame buffer definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#ifndef _ASM_UBICOM32_UBICOM32FB_H +#define _ASM_UBICOM32_UBICOM32FB_H + +#include + +/* + * Set next frame + */ +#define UBICOM32FB_IOCTL_SET_NEXT_FRAME _IOW('r', 1, void *) +#define UBICOM32FB_IOCTL_SET_NEXT_FRAME_SYNC _IOW('r', 2, void *) + +/* + * Set Mode + */ +#define UBICOM32FB_IOCTL_SET_MODE _IOW('r', 3, void *) +struct ubicom32fb_mode { + unsigned long width; + unsigned long height; + unsigned long flags; + void *next_frame; +}; +#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_SCAN_ORDER (1 << 8) + +#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_BLOCK_ORDER (1 << 7) +#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV (1 << 6) +#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VSUB (1 << 5) +#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_16_255 (1 << 4) + +#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_0_255 (1 << 3) +#define UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_2_1 (1 << 2) +#define UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_1_1 (1 << 1) +#define UBICOM32FB_IOCTL_SET_MODE_FLAG_SCALE_ENABLE (1 << 0) + +#endif /* _ASM_UBICOM32_UBICOM32FB_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32hid.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32hid.h new file mode 100644 index 000000000..d324313f1 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32hid.h @@ -0,0 +1,133 @@ +/* + * arch/ubicom32/include/asm/ubicom32hid.h + * Ubicom32 architecture HID driver platform data definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_UBICOM32_HID_H +#define _ASM_UBICOM32_UBICOM32_HID_H + +enum ubicom32hid_bl_types { + /* + * On or off, using command SET_BL_EN, PB4 + */ + UBICOM32HID_BL_TYPE_BINARY, + + /* + * Dimmable, using command SET_PWM, PB3 + */ + UBICOM32HID_BL_TYPE_PWM, +}; + +/* + * IR code mapping to event code. + * If there are no button mappings and no ir mappings + * then no input driver will be registered. + */ +struct ubicom32hid_ir { + /* + * Input event code (KEY_*, SW_*, etc) + */ + int code; + + /* + * Input event type (EV_KEY, EV_SW, etc) + */ + int type; + + /* + * The IR code of this button. + */ + uint32_t ir_code; +}; + +/* + * Button mapping to event code. + * If there are no button mappings and no ir mappings + * then no input driver will be registered. + */ +struct ubicom32hid_button { + /* + * Input event code (KEY_*, SW_*, etc) + */ + int code; + + /* + * Input event type (EV_KEY, EV_SW, etc) + */ + int type; + + /* + * Bit number of this button. + */ + uint8_t bit; +}; + +struct ubicom32hid_platform_data { + /* + * Default intensity of the backlight 0-255 + */ + u8_t default_intensity; + + /* + * GPIO number of the reset line and its polarity. + */ + unsigned gpio_reset; + int gpio_reset_polarity; + + /* + * TRUE if the backlight sense is active low. (inverted) + * FALSE if the backlight sense is active high. + */ + bool invert; + + /* + * Type of the backlight we are controlling + */ + enum ubicom32hid_bl_types type; + + /* + * Optional polling rate for input, in ms, defaults to 100ms + */ + int poll_interval; + + /* + * Optional name to register as input device + */ + const char *input_name; + + /* + * Button mapping array + */ + const struct ubicom32hid_button *buttons; + int nbuttons; + + /* + * IR mapping array + */ + const struct ubicom32hid_ir *ircodes; + int nircodes; +}; + +#endif /* _ASM_UBICOM32_UBICOM32_HID_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input.h new file mode 100644 index 000000000..dea5c7928 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input.h @@ -0,0 +1,76 @@ +/* + * arch/ubicom32/include/asm/ubicom32input.h + * Ubicom32 Input driver, based on gpio-keys + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * + * TODO: add groups for inputs which can be sampled together + */ + +#ifndef _ASM_UBICOM32_UBICOM32_INPUT_H +#define _ASM_UBICOM32_UBICOM32_INPUT_H + +struct ubicom32input_button { + /* + * Input event code (KEY_*, SW_*, etc) + */ + int code; + + /* + * Input event type (EV_KEY, EV_SW, etc) + */ + int type; + + /* + * GPIO to poll + */ + int gpio; + + /* + * 1 for active low, 0 for active high + */ + int active_low; + + /* + * Description, used for reserving GPIOs + */ + const char *desc; +}; + +struct ubicom32input_platform_data { + struct ubicom32input_button *buttons; + int nbuttons; + + /* + * Optional poll interval, in ms, defaults to 50ms + */ + int poll_interval; + + /* + * Option Name of this driver + */ + const char *name; +}; + +#endif /* _ASM_UBICOM32_UBICOM32_INPUT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input_i2c.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input_i2c.h new file mode 100644 index 000000000..eb1672375 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input_i2c.h @@ -0,0 +1,71 @@ +/* + * arch/ubicom32/include/asm/ubicom32input_i2c.h + * Ubicom32 architecture Input driver over I2C platform data definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * + * TODO: add groups for inputs which can be sampled together + */ + +#ifndef _ASM_UBICOM32_UBICOM32_INPUT_I2C_H +#define _ASM_UBICOM32_UBICOM32_INPUT_I2C_H + +struct ubicom32input_i2c_button { + /* + * Input event code (KEY_*, SW_*, etc) + */ + int code; + + /* + * Input event type (EV_KEY, EV_SW, etc) + */ + int type; + + /* + * Bit number of this button. (0 - ngpio) + */ + int bit; + + /* + * 1 for active low, 0 for active high + */ + int active_low; +}; + +struct ubicom32input_i2c_platform_data { + struct ubicom32input_i2c_button *buttons; + int nbuttons; + + /* + * Optional poll interval, in ms, defaults to 100ms + */ + int poll_interval; + + /* + * Option Name of this driver + */ + const char *name; +}; + +#endif /* _ASM_UBICOM32_UBICOM32_INPUT_I2C_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcd.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcd.h new file mode 100644 index 000000000..eea5340fd --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcd.h @@ -0,0 +1,38 @@ +/* + * arch/ubicom32/include/asm/ubicom32lcd.h + * Ubicom32 architecture LCD driver platform data definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#ifndef _ASM_UBICOM32_UBICOM32_LCD_H +#define _ASM_UBICOM32_UBICOM32_LCD_H + +#include + +struct ubicom32lcd_platform_data { + int pin_cs; + int pin_rs; + int pin_rd; + int pin_wr; + int pin_reset; + int data_shift; + struct ubicom32_io_port *port_data; +}; + +#endif /* _ASM_UBICOM32_UBICOM32_LCD_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcdpower.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcdpower.h new file mode 100644 index 000000000..03b8a7eaa --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcdpower.h @@ -0,0 +1,39 @@ +/* + * arch/ubicom32/include/asm/ubicom32lcdpower.h + * Ubicom32 architecture LCD driver platform data definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_UBICOM32_LCDPOWER_H +#define _ASM_UBICOM32_UBICOM32_LCDPOWER_H + +struct ubicom32lcdpower_platform_data { + /* + * GPIO and polarity for VGH signal. A FALSE polarity is active low, TRUE is active high. + */ + int vgh_gpio; + bool vgh_polarity; +}; + +#endif /* _ASM_UBICOM32_UBICOM32_LCDPOWER_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32ring.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32ring.h new file mode 100644 index 000000000..dd9c8f76c --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32ring.h @@ -0,0 +1,103 @@ +/* + * arch/ubicom32/include/asm/ubicom32ring.h + * Userspace I/O platform driver for Ubicom32 ring buffers + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#ifndef _ASM_UBICOM32_UBICOM32RING_H +#define _ASM_UBICOM32_UBICOM32RING_H + +#define UIO_UBICOM32RING_REG_VERSION 2 + +struct uio_ubicom32ring_desc { + volatile unsigned int head; + volatile unsigned int tail; + unsigned int entries; + volatile unsigned int ring[0]; +}; + +struct uio_ubicom32ring_regs { + unsigned int version; + + /* + * Magic type used to identify the ring set. Each driver will + * have a different magic value. + */ + unsigned int magic; + + /* + * Registers defined by the driver + */ + unsigned int regs_size; + void *regs; + + /* + * The locations of the rings + * + * DO NOT ADD ANYTHING BELOW THIS LINE + */ + unsigned int num_rings; + struct uio_ubicom32ring_desc *rings[0]; +}; + +/* + * ringtio_ring_flush + */ +static inline void ringtio_ring_flush(struct uio_ubicom32ring_desc *rd) +{ + rd->head = rd->tail = 0; +} + +/* + * ringtio_ring_get + */ +static inline int ringtio_ring_get(struct uio_ubicom32ring_desc *rd, void **val) +{ + if (rd->head == rd->tail) { + return 0; + } + + *val = (void *)rd->ring[rd->head++]; + if (rd->head == rd->entries) { + rd->head = 0; + } + return 1; +} + +/* + * ringtio_ring_put + */ +static inline int ringtio_ring_put(struct uio_ubicom32ring_desc *rd, void *val) +{ + unsigned int newtail = rd->tail + 1; + if (newtail == rd->entries) { + newtail = 0; + } + + if (newtail == rd->head) { + return 0; + } + + rd->ring[rd->tail] = (unsigned int)val; + rd->tail = newtail; + return 1; +} + +#endif /* _ASM_UBICOM32_UBICOM32RING_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32sd.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32sd.h new file mode 100644 index 000000000..b5cebfa2e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32sd.h @@ -0,0 +1,45 @@ +/* + * arch/ubicom32/include/asm/ubicom32sd.h + * Ubicom32SD public include file + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#ifndef _ASM_UBICOM32_UBICOM32_SD_H +#define _ASM_UBICOM32_UBICOM32_SD_H + +struct ubicom32sd_card { + /* + * GPIOs of PWR, WP and CD lines. + * Polarity is 1 for active high and 0 for active low + */ + int pin_pwr; + bool pwr_polarity; + int pin_wp; + bool wp_polarity; + int pin_cd; + bool cd_polarity; +}; + +struct ubicom32sd_platform_data { + int ncards; + + struct ubicom32sd_card *cards; +}; + +#endif /* _ASM_UBICOM32_UBICOM32_SD_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32suart.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32suart.h new file mode 100644 index 000000000..824d0de2e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32suart.h @@ -0,0 +1,36 @@ +/* + * arch/ubicom32/include/asm/ubicom32suart.h + * + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_UBICOM32_SUART_H +#define _ASM_UBICOM32_UBICOM32_SUART_H + +/* + * Platform resource id for serdes uart clock parameter + */ +#define UBICOM32_SUART_IORESOURCE_CLOCK (1) + +#endif /* _ASM_UBICOM32_UBICOM32_SUART_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ucontext.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ucontext.h new file mode 100644 index 000000000..71c112902 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ucontext.h @@ -0,0 +1,39 @@ +/* + * arch/ubicom32/include/asm/ucontext.h + * Definition of ucontext structure for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_UCONTEXT_H +#define _ASM_UBICOM32_UCONTEXT_H + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif /* _ASM_UBICOM32_UCONTEXT_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/unaligned.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/unaligned.h new file mode 100644 index 000000000..41b264660 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/unaligned.h @@ -0,0 +1,44 @@ +/* + * arch/ubicom32/include/asm/unaligned.h + * Ubicom32 architecture unaligned memory access definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * + * TODO: This is a copy of arm unaligned handling that probably needs + * to be optimized for UBICOM32, but it works for now. + */ + +#ifndef _ASM_UBICOM32_UNALIGNED_H +#define _ASM_UBICOM32_UNALIGNED_H + +#include + +#include +#include +#include + +#define get_unaligned __get_unaligned_be +#define put_unaligned __put_unaligned_be + +#endif /* _ASM_UBICOM32_UNALIGNED_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/unistd.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/unistd.h new file mode 100644 index 000000000..2c7ba5600 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/unistd.h @@ -0,0 +1,400 @@ +/* + * arch/ubicom32/include/asm/unistd.h + * Ubicom32 architecture syscall definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_UNISTD_H +#define _ASM_UBICOM32_UNISTD_H + +/* + * This file contains the system call numbers. + */ + +#define __NR_restart_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl /* 110 */ not supported +#define __NR_vhangup 111 +#define __NR_idle /* 112 */ Obsolete +#define __NR_vm86 /* 113 */ not supported +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_cacheflush 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_getpagesize 166 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread64 180 +#define __NR_pwrite64 181 +#define __NR_lchown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_getpmsg 188 /* some people actually want streams */ +#define __NR_putpmsg 189 /* some people actually want streams */ +#define __NR_vfork 190 +#define __NR_ugetrlimit 191 +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_chown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_lchown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 +#define __NR_getdents64 220 +#define __NR_gettid 221 +#define __NR_tkill 222 +#define __NR_setxattr 223 +#define __NR_lsetxattr 224 +#define __NR_fsetxattr 225 +#define __NR_getxattr 226 +#define __NR_lgetxattr 227 +#define __NR_fgetxattr 228 +#define __NR_listxattr 229 +#define __NR_llistxattr 230 +#define __NR_flistxattr 231 +#define __NR_removexattr 232 +#define __NR_lremovexattr 233 +#define __NR_fremovexattr 234 +#define __NR_futex 235 +#define __NR_sendfile64 236 +#define __NR_mincore 237 +#define __NR_madvise 238 +#define __NR_fcntl64 239 +#define __NR_readahead 240 +#define __NR_io_setup 241 +#define __NR_io_destroy 242 +#define __NR_io_getevents 243 +#define __NR_io_submit 244 +#define __NR_io_cancel 245 +#define __NR_fadvise64 246 +#define __NR_exit_group 247 +#define __NR_lookup_dcookie 248 +#define __NR_epoll_create 249 +#define __NR_epoll_ctl 250 +#define __NR_epoll_wait 251 +#define __NR_remap_file_pages 252 +#define __NR_set_tid_address 253 +#define __NR_timer_create 254 +#define __NR_timer_settime 255 +#define __NR_timer_gettime 256 +#define __NR_timer_getoverrun 257 +#define __NR_timer_delete 258 +#define __NR_clock_settime 259 +#define __NR_clock_gettime 260 +#define __NR_clock_getres 261 +#define __NR_clock_nanosleep 262 +#define __NR_statfs64 263 +#define __NR_fstatfs64 264 +#define __NR_tgkill 265 +#define __NR_utimes 266 +#define __NR_fadvise64_64 267 +#define __NR_mbind 268 +#define __NR_get_mempolicy 269 +#define __NR_set_mempolicy 270 +#define __NR_mq_open 271 +#define __NR_mq_unlink 272 +#define __NR_mq_timedsend 273 +#define __NR_mq_timedreceive 274 +#define __NR_mq_notify 275 +#define __NR_mq_getsetattr 276 +#define __NR_waitid 277 +#define __NR_vserver 278 +#define __NR_add_key 279 +#define __NR_request_key 280 +#define __NR_keyctl 281 +#define __NR_ioprio_set 282 +#define __NR_ioprio_get 283 +#define __NR_inotify_init 284 +#define __NR_inotify_add_watch 285 +#define __NR_inotify_rm_watch 286 +#define __NR_migrate_pages 287 +#define __NR_openat 288 +#define __NR_mkdirat 289 +#define __NR_mknodat 290 +#define __NR_fchownat 291 +#define __NR_futimesat 292 +#define __NR_fstatat64 293 +#define __NR_unlinkat 294 +#define __NR_renameat 295 +#define __NR_linkat 296 +#define __NR_symlinkat 297 +#define __NR_readlinkat 298 +#define __NR_fchmodat 299 +#define __NR_faccessat 300 +#define __NR_pselect6 301 +#define __NR_ppoll 302 +#define __NR_unshare 303 +#define __NR_set_robust_list 304 +#define __NR_get_robust_list 305 +#define __NR_splice 306 +#define __NR_sync_file_range 307 +#define __NR_tee 308 +#define __NR_vmsplice 309 +#define __NR_move_pages 310 +#define __NR_sched_setaffinity 311 +#define __NR_sched_getaffinity 312 +#define __NR_kexec_load 313 +#define __NR_getcpu 314 +#define __NR_epoll_pwait 315 +#define __NR_utimensat 316 +#define __NR_signalfd 317 +#define __NR_timerfd_create 318 +#define __NR_eventfd 319 +#define __NR_fallocate 320 +#define __NR_timerfd_settime 321 +#define __NR_timerfd_gettime 322 +#define __NR_signalfd4 323 +#define __NR_eventfd2 324 +#define __NR_epoll_create1 325 +#define __NR_dup3 326 +#define __NR_pipe2 327 +#define __NR_inotify_init1 328 + +#ifdef __KERNEL__ + +#define NR_syscalls 329 + +#define __ARCH_WANT_IPC_PARSE_VERSION +#define __ARCH_WANT_OLD_READDIR +#define __ARCH_WANT_OLD_STAT +#define __ARCH_WANT_STAT64 +#define __ARCH_WANT_SYS_ALARM +#define __ARCH_WANT_SYS_GETHOSTNAME +#define __ARCH_WANT_SYS_PAUSE +#define __ARCH_WANT_SYS_SGETMASK +#define __ARCH_WANT_SYS_SIGNAL +#define __ARCH_WANT_SYS_TIME +#define __ARCH_WANT_SYS_UTIME +#define __ARCH_WANT_SYS_WAITPID +#define __ARCH_WANT_SYS_SOCKETCALL +#define __ARCH_WANT_SYS_FADVISE64 +#define __ARCH_WANT_SYS_GETPGRP +#define __ARCH_WANT_SYS_LLSEEK +#define __ARCH_WANT_SYS_NICE +#define __ARCH_WANT_SYS_OLD_GETRLIMIT +#define __ARCH_WANT_SYS_OLDUMOUNT +#define __ARCH_WANT_SYS_SIGPENDING +#define __ARCH_WANT_SYS_SIGPROCMASK +#define __ARCH_WANT_SYS_RT_SIGACTION + +/* + * "Conditional" syscalls + * + * What we want is __attribute__((weak,alias("sys_ni_syscall"))), + * but it doesn't work on all toolchains, so we just do it by hand + */ +//#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#define cond_syscall(x) long x(void) __attribute__((weak,alias("sys_ni_syscall"))) +#endif /* __KERNEL__ */ + +#endif /* _ASM_UBICOM32_UNISTD_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/user.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/user.h new file mode 100644 index 000000000..2e79786ca --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/user.h @@ -0,0 +1,82 @@ +/* + * arch/ubicom32/include/asm/user.h + * Ubicom32 architecture core file definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_USER_H +#define _ASM_UBICOM32_USER_H + +#include +#include +/* + * Adapted from + * + * Core file format: The core file is written in such a way that gdb + * can understand it and provide useful information to the user (under + * linux we use the `trad-core' bfd, NOT the osf-core). The file contents + * are as follows: + * + * upage: 1 page consisting of a user struct that tells gdb + * what is present in the file. Directly after this is a + * copy of the task_struct, which is currently not used by gdb, + * but it may come in handy at some point. All of the registers + * are stored as part of the upage. The upage should always be + * only one page long. + * data: The data segment follows next. We use current->end_text to + * current->brk to pick up all of the user variables, plus any memory + * that may have been sbrk'ed. No attempt is made to determine if a + * page is demand-zero or if a page is totally unused, we just cover + * the entire range. All of the addresses are rounded in such a way + * that an integral number of pages is written. + * stack: We need the stack information in order to get a meaningful + * backtrace. We need to write the data from usp to + * current->start_stack, so we round each of these in order to be able + * to write an integer number of pages. + */ + +struct user_ubicom32fp_struct { +}; + +struct user { + struct pt_regs regs; /* entire machine state */ + size_t u_tsize; /* text size (pages) */ + size_t u_dsize; /* data size (pages) */ + size_t u_ssize; /* stack size (pages) */ + unsigned long start_code; /* text starting address */ + unsigned long start_data; /* data starting address */ + unsigned long start_stack; /* stack starting address */ + long int signal; /* signal causing core dump */ + unsigned long u_ar0; /* help gdb find registers */ + unsigned long magic; /* identifies a core file */ + char u_comm[32]; /* user command name */ +}; + +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_DATA_START_ADDR (u.start_data) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif /* _ASM_UBICOM32_USER_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/vdc_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/vdc_tio.h new file mode 100644 index 000000000..cc45fc552 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/vdc_tio.h @@ -0,0 +1,129 @@ +/* + * arch/ubicom32/include/asm/vdc_tio.h + * Ubicom32 architecture VDC TIO definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_VDC_TIO_H +#define _ASM_UBICOM32_VDC_TIO_H + +#include + +#define VDCTIO_VP_VERSION 5 + +#define VDCTIO_SCALE_FLAG_VSUB (1 << 9) +#define VDCTIO_SCALE_FLAG_YUV_SCAN_ORDER (1 << 8) +#define VDCTIO_SCALE_FLAG_YUV_BLOCK_ORDER (1 << 7) +#define VDCTIO_SCALE_FLAG_YUV (1 << 6) +#define VDCTIO_SCALE_FLAG_VRANGE_16_255 (1 << 5) +#define VDCTIO_SCALE_FLAG_VRANGE_0_255 (1 << 4) +#define VDCTIO_SCALE_FLAG_HSUB_2_1 (1 << 3) +#define VDCTIO_SCALE_FLAG_HSUB_1_1 (1 << 2) +#define VDCTIO_SCALE_FLAG_SET_FRAME_BUFFER (1 << 1) +#define VDCTIO_SCALE_FLAG_ENABLE (1 << 0) + +#define VDCTIO_NEXT_FRAME_FLAG_YUV_BIT 0 +#define VDCTIO_NEXT_FRAME_FLAG_YUV (1 << (VDCTIO_NEXT_FRAME_FLAG_YUV_BIT)) + +#define VDCTIO_CAPS_SUPPORTS_SCALING (1 << 0) + +#define VDCTIO_COMMAND_START (1 << 3) +#define VDCTIO_COMMAND_SET_COEFF (1 << 2) +#define VDCTIO_COMMAND_SET_LUT (1 << 1) +#define VDCTIO_COMMAND_SET_SCALE_MODE (1 << 0) + +/* + * Command / Data registers to access the VDC + */ +struct vdc_tio_vp_regs { + /* + * Version of this TIO register map + */ + u32_t version; + + volatile u32_t command; + + /* + * Next frame pointer, when the command VDCTIO_COMMAND_SET_FRAME_BUFFER is set, + * the vdc will take the pointer here and display it. + */ + void *next_frame; + u32_t next_frame_flags; + + /* + * These map directly into the PIXP registers 0x20-0x80. + * DO NOT change the order of these three variables. + */ + u32_t red_lut[6]; + u32_t blue_lut[6]; + u32_t green_lut[13]; + + /* + * These map directly into the PIXP registers 0x04, 0x08 + */ + u32_t coeff0; + u32_t coeff1; + + /* + * There are used to set the scaling parameters + */ + u32_t x_in; + u32_t x_out; + u32_t y_in; + u32_t y_out; + u32_t scale_flags; + + /* + * Current frame number, monotonically increasing number + */ + u32_t frame_number; + + /* + * These variables tell the guest OS what the underlying hardware looks like + */ + u32_t caps; + u32_t xres; + u32_t yres; + u32_t fb_align; + u8_t bpp; + u8_t rbits; + u8_t gbits; + u8_t bbits; + u8_t rshift; + u8_t gshift; + u8_t bshift; +}; + +/* + * Devtree node for VDC + */ +struct vdc_tio_node { + struct devtree_node dn; + + struct vdc_tio_vp_regs *regs; +}; + +extern void vdc_tio_init(void); + +#endif /* _ASM_UBICOM32_VDC_TIO_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/vga.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/vga.h new file mode 100644 index 000000000..793435f8b --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/vga.h @@ -0,0 +1,71 @@ +/* + * arch/ubicom32/include/asm/vga.h + * Ubicom32 low level VGA/frame buffer definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * (c) 1998 Martin Mares + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#ifndef _ASM_UBICOM32_VGA_H +#define _ASM_UBICOM32_VGA_H + +#include + +/* + * On the PC, we can just recalculate addresses and then + * access the videoram directly without any black magic. + */ + +#define VGA_MAP_MEM(x, s) (0xb0000000L + (unsigned long)(x)) + +#define vga_readb(x) (*(x)) +#define vga_writeb(x, y) (*(y) = (x)) + +#define VT_BUF_HAVE_RW +/* + * These are only needed for supporting VGA or MDA text mode, which use little + * endian byte ordering. + * In other cases, we can optimize by using native byte ordering and + * has already done the right job for us. + */ + +#undef scr_writew +#undef scr_readw + +static inline void scr_writew(u16 val, volatile u16 *addr) +{ + *addr = cpu_to_le16(val); +} + +static inline u16 scr_readw(volatile const u16 *addr) +{ + return le16_to_cpu(*addr); +} + +#define scr_memcpyw(d, s, c) memcpy(d, s, c) +#define scr_memmovew(d, s, c) memmove(d, s, c) +#define VT_BUF_HAVE_MEMCPYW +#define VT_BUF_HAVE_MEMMOVEW + +#endif /* _ASM_UBICOM32_VGA_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/xor.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/xor.h new file mode 100644 index 000000000..31edcceb6 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/include/asm/xor.h @@ -0,0 +1,33 @@ +/* + * arch/ubicom32/include/asm/xor.h + * Generic xor.h definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _ASM_UBICOM32_XOR_H +#define _ASM_UBICOM32_XOR_H + +#include + +#endif /* _ASM_UBICOM32_XOR_H */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/Makefile b/target/linux/ubicom32/files/arch/ubicom32/kernel/Makefile new file mode 100644 index 000000000..6294fa2ea --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/Makefile @@ -0,0 +1,64 @@ +# +# arch/ubicom32/kernel/Makefile +# Main Makefile for the Ubicom32 arch directory. +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# + +extra-y := head.o vmlinux.lds + +obj-y += \ + devtree.o \ + dma.o \ + flat.o \ + init_task.o \ + irq.o \ + ldsr.o \ + os_node.o \ + process.o \ + processor.o \ + ptrace.o \ + setup.o \ + signal.o \ + stacktrace.o \ + sys_ubicom32.o \ + syscalltable.o \ + thread.o \ + time.o \ + traps.o \ + ubicom32_context_switch.o \ + ubicom32_ksyms.o \ + ubicom32_syscall.o \ + unaligned_trap.o + +obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_COMEMPCI) += comempci.o +obj-$(CONFIG_SMP) += smp.o topology.o +obj-$(CONFIG_ACCESS_OK_CHECKS_ENABLED) += uaccess.o +obj-$(CONFIG_GENERIC_CLOCKEVENTS) += timer_device.o +obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += timer_broadcast.o + +ifndef CONFIG_GENERIC_CLOCKEVENTS +obj-y += timer_tick.o +endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/asm-offsets.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/asm-offsets.c new file mode 100644 index 000000000..639a536a1 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/asm-offsets.c @@ -0,0 +1,161 @@ +/* + * arch/ubicom32/kernel/asm-offsets.c + * Ubicom32 architecture definitions needed by assembly language modules. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + /* offsets into the task struct */ + DEFINE(TASK_STATE, offsetof(struct task_struct, state)); + DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); + DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); + DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); + DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack)); + DEFINE(TASK_MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); + + /* offsets into the kernel_stat struct */ +// DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); + + /* offsets into the irq_cpustat_t struct */ + DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); + + /* offsets into the thread struct */ + DEFINE(THREAD_D10, offsetof(struct thread_struct, d10)); + DEFINE(THREAD_D11, offsetof(struct thread_struct, d11)); + DEFINE(THREAD_D12, offsetof(struct thread_struct, d12)); + DEFINE(THREAD_D13, offsetof(struct thread_struct, d13)); + DEFINE(THREAD_A1, offsetof(struct thread_struct, a1)); + DEFINE(THREAD_A2, offsetof(struct thread_struct, a2)); + DEFINE(THREAD_A5, offsetof(struct thread_struct, a5)); + DEFINE(THREAD_A6, offsetof(struct thread_struct, a6)); + DEFINE(THREAD_SP, offsetof(struct thread_struct, sp)); + + /* offsets into the pt_regs */ + DEFINE(PT_D0, offsetof(struct pt_regs, dn[0])); + DEFINE(PT_D1, offsetof(struct pt_regs, dn[1])); + DEFINE(PT_D2, offsetof(struct pt_regs, dn[2])); + DEFINE(PT_D3, offsetof(struct pt_regs, dn[3])); + DEFINE(PT_D4, offsetof(struct pt_regs, dn[4])); + DEFINE(PT_D5, offsetof(struct pt_regs, dn[5])); + DEFINE(PT_D6, offsetof(struct pt_regs, dn[6])); + DEFINE(PT_D7, offsetof(struct pt_regs, dn[7])); + DEFINE(PT_D8, offsetof(struct pt_regs, dn[8])); + DEFINE(PT_D9, offsetof(struct pt_regs, dn[9])); + DEFINE(PT_D10, offsetof(struct pt_regs, dn[10])); + DEFINE(PT_D11, offsetof(struct pt_regs, dn[11])); + DEFINE(PT_D12, offsetof(struct pt_regs, dn[12])); + DEFINE(PT_D13, offsetof(struct pt_regs, dn[13])); + DEFINE(PT_D14, offsetof(struct pt_regs, dn[14])); + DEFINE(PT_D15, offsetof(struct pt_regs, dn[15])); + DEFINE(PT_A0, offsetof(struct pt_regs, an[0])); + DEFINE(PT_A1, offsetof(struct pt_regs, an[1])); + DEFINE(PT_A2, offsetof(struct pt_regs, an[2])); + DEFINE(PT_A3, offsetof(struct pt_regs, an[3])); + DEFINE(PT_A4, offsetof(struct pt_regs, an[4])); + DEFINE(PT_A5, offsetof(struct pt_regs, an[5])); + DEFINE(PT_A6, offsetof(struct pt_regs, an[6])); + DEFINE(PT_A7, offsetof(struct pt_regs, an[7])); + DEFINE(PT_SP, offsetof(struct pt_regs, an[7])); + + DEFINE(PT_ACC0HI, offsetof(struct pt_regs, acc0[0])); + DEFINE(PT_ACC0LO, offsetof(struct pt_regs, acc0[1])); + DEFINE(PT_MAC_RC16, offsetof(struct pt_regs, mac_rc16)); + + DEFINE(PT_ACC1HI, offsetof(struct pt_regs, acc1[0])); + DEFINE(PT_ACC1LO, offsetof(struct pt_regs, acc1[1])); + + DEFINE(PT_SOURCE3, offsetof(struct pt_regs, source3)); + DEFINE(PT_INST_CNT, offsetof(struct pt_regs, inst_cnt)); + DEFINE(PT_CSR, offsetof(struct pt_regs, csr)); + DEFINE(PT_DUMMY_UNUSED, offsetof(struct pt_regs, dummy_unused)); + + DEFINE(PT_INT_MASK0, offsetof(struct pt_regs, int_mask0)); + DEFINE(PT_INT_MASK1, offsetof(struct pt_regs, int_mask1)); + + DEFINE(PT_PC, offsetof(struct pt_regs, pc)); + + DEFINE(PT_TRAP_CAUSE, offsetof(struct pt_regs, trap_cause)); + + DEFINE(PT_SIZE, sizeof(struct pt_regs)); + + DEFINE(PT_FRAME_TYPE, offsetof(struct pt_regs, frame_type)); + + DEFINE(PT_ORIGINAL_D0, offsetof(struct pt_regs, original_dn_0)); + DEFINE(PT_PREVIOUS_PC, offsetof(struct pt_regs, previous_pc)); + + /* offsets into the kernel_stat struct */ +// DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); + + /* signal defines */ + DEFINE(SIGSEGV, SIGSEGV); + //DEFINE(SEGV_MAPERR, SEGV_MAPERR); + DEFINE(SIGTRAP, SIGTRAP); + //DEFINE(TRAP_TRACE, TRAP_TRACE); + + DEFINE(PT_PTRACED, PT_PTRACED); + DEFINE(PT_DTRACE, PT_DTRACE); + + DEFINE(ASM_THREAD_SIZE, THREAD_SIZE); + + /* Offsets in thread_info structure */ + DEFINE(TI_TASK, offsetof(struct thread_info, task)); + DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); + DEFINE(TI_INTR_NESTING, offsetof(struct thread_info, interrupt_nesting)); + DEFINE(ASM_TIF_NEED_RESCHED, TIF_NEED_RESCHED); + DEFINE(ASM_TIF_SYSCALL_TRACE, TIF_SYSCALL_TRACE); + DEFINE(ASM_TIF_SIGPENDING, TIF_SIGPENDING); + + return 0; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/devtree.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/devtree.c new file mode 100644 index 000000000..1f824d2f1 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/devtree.c @@ -0,0 +1,173 @@ +/* + * arch/ubicom32/kernel/devtree.c + * Ubicom32 architecture device tree implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include + +/* + * The device tree. + */ +struct devtree_node *devtree; + +/* + * devtree_print() + * Print the device tree. + */ +void devtree_print(void) +{ + struct devtree_node *p = devtree; + printk(KERN_INFO "Device Tree:\n"); + while (p) { + if (p->magic != DEVTREE_NODE_MAGIC) { + printk(KERN_EMERG + "device tree has improper node: %p\n", p); + return; + } + printk(KERN_INFO "\t%p: sendirq=%03d, recvirq=%03d, " + " name=%s\n", p, p->sendirq, p->recvirq, p->name); + p = p->next; + } +} +EXPORT_SYMBOL(devtree_print); + +/* + * devtree_irq() + * Return the IRQ(s) associated with devtree node. + */ +int devtree_irq(struct devtree_node *dn, + unsigned char *sendirq, + unsigned char *recvirq) +{ + if (dn->magic != DEVTREE_NODE_MAGIC) { + printk(KERN_EMERG "improper node: %p\n", dn); + if (sendirq) { + *sendirq = DEVTREE_IRQ_NONE; + } + if (recvirq) { + *recvirq = DEVTREE_IRQ_NONE; + } + return -EFAULT; + } + + /* + * Copy the devtree irq(s) to the output parameters. + */ + if (sendirq) { + *sendirq = dn->sendirq; + } + if (recvirq) { + *recvirq = dn->recvirq; + } + return 0; +} +EXPORT_SYMBOL(devtree_irq); + +/* + * devtree_find_next() + * Provide an iterator for walking the device tree. + */ +struct devtree_node *devtree_find_next(struct devtree_node **cur) +{ + struct devtree_node *p = *cur; + if (!p) { + *cur = devtree; + return devtree; + } + p = p->next; + *cur = p; + return p; +} + +/* + * devtree_find_by_irq() + * Return the node associated with a given irq. + */ +struct devtree_node *devtree_find_by_irq(uint8_t sendirq, uint8_t recvirq) +{ + struct devtree_node *p = devtree; + + if (sendirq == recvirq) { + printk(KERN_EMERG "identical request makes no sense sendirq = " + "%d, recvirq= %d\n", sendirq, recvirq); + return NULL; + } + + while (p) { + if (p->magic != DEVTREE_NODE_MAGIC) { + printk(KERN_EMERG + "device tree has improper node: %p\n", p); + return NULL; + } + + /* + * See if we can find a match on the IRQ(s) specified. + */ + if ((sendirq == p->sendirq) && (recvirq == p->recvirq)) { + return p; + } + + if ((sendirq == DEVTREE_IRQ_DONTCARE) && + (p->recvirq == recvirq)) { + return p; + } + + if ((recvirq == DEVTREE_IRQ_DONTCARE) && + (p->sendirq == sendirq)) { + return p; + } + + p = p->next; + } + return NULL; +} +EXPORT_SYMBOL(devtree_find_by_irq); + +/* + * devtree_find_node() + * Find a node in the device tree by name. + */ +struct devtree_node *devtree_find_node(const char *str) +{ + struct devtree_node *p = devtree; + while (p) { + if (p->magic != DEVTREE_NODE_MAGIC) { + printk(KERN_EMERG + "device tree has improper node: %p\n", p); + return NULL; + } + if (strcmp(p->name, str) == 0) { + return p; + } + p = p->next; + } + return NULL; +} +EXPORT_SYMBOL(devtree_find_node); diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/dma.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/dma.c new file mode 100644 index 000000000..f61810532 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/dma.c @@ -0,0 +1,60 @@ +/* + * arch/ubicom32/kernel/dma.c + * Ubicom32 architecture dynamic DMA mapping support. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * + * We never have any address translations to worry about, so this + * is just alloc/free. + */ + +#include +#include +#include +#include +#include + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, int gfp) +{ + void *ret; + /* ignore region specifiers */ + gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + + if (dev == NULL || (*dev->dma_mask < 0xffffffff)) + gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_phys(ret); + } + return ret; +} + +void dma_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, get_order(size)); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/flat.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/flat.c new file mode 100644 index 000000000..e8eb4595f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/flat.c @@ -0,0 +1,206 @@ +/* + * arch/ubicom32/kernel/flat.c + * Ubicom32 architecture flat executable format support. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include + +unsigned long ubicom32_flat_get_addr_from_rp(unsigned long *rp, + u32_t relval, + u32_t flags, + unsigned long *persistent) +{ + u32_t relval_reloc_type = relval >> 27; + u32_t insn = *rp; + + if (*persistent) { + /* + * relval holds the relocation that has to be adjusted. + */ + if (relval == 0) { + *persistent = 0; + } + + return relval; + } + + if (relval_reloc_type == R_UBICOM32_32) { + /* + * insn holds the relocation + */ + return insn; + } + + /* + * We don't know this one. + */ + return 0; +} + +void ubicom32_flat_put_addr_at_rp(unsigned long *rp, + u32_t val, + u32_t relval, + unsigned long *persistent) +{ + u32_t reloc_type = (relval >> 27) & 0x1f; + u32_t insn = *rp; + + /* + * If persistent is set then it contains the relocation type. + */ + if (*persistent) { + /* + * If persistent is set then it contains the relocation type. + */ + reloc_type = (*persistent >> 27) & 0x1f; + } + + switch (reloc_type) { + case R_UBICOM32_32: + /* + * Store the 32 bits as is. + */ + *rp = val; + break; + case R_UBICOM32_HI24: + { + /* + * 24 bit relocation that is part of the MOVEAI + * instruction. The 24 bits come from bits 7 - 30 of the + * relocation. The 24 bits eventually get split into 2 + * fields in the instruction encoding. + * + * - Bits 7 - 27 of the relocation are encoded into bits + * 0 - 20 of the instruction. + * + * - Bits 28 - 30 of the relocation are encoded into bit + * 24 - 26 of the instruction. + */ + u32_t mask = 0x1fffff | (0x7 << 24); + u32_t valid24bits = (val >> 7) & 0xffffff; + u32_t bot_21 = valid24bits & 0x1fffff; + u32_t upper_3_bits = ((valid24bits & 0xe00000) << 3); + insn &= ~mask; + + insn |= bot_21; + insn |= upper_3_bits; + *rp = insn; + } + break; + case R_UBICOM32_LO7_S: + case R_UBICOM32_LO7_2_S: + case R_UBICOM32_LO7_4_S: + { + /* + * Bits 0 - 6 of the relocation are encoded into the + * 7bit unsigned immediate fields of the SOURCE-1 field + * of the instruction. The immediate value is left + * shifted by (0, 1, 2) based on the operand size. + */ + u32_t mask = 0x1f | (0x3 << 8); + u32_t bottom, top; + val &= 0x7f; + if (reloc_type == R_UBICOM32_LO7_2_S) { + val >>= 1; + } else if (reloc_type == R_UBICOM32_LO7_4_S) { + val >>= 2; + } + + bottom = val & 0x1f; + top = val >> 5; + insn &= ~mask; + insn |= bottom; + insn |= (top << 8); + BUG_ON(*rp != insn); + *rp = insn; + break; + } + case R_UBICOM32_LO7_D: + case R_UBICOM32_LO7_2_D: + case R_UBICOM32_LO7_4_D: + { + /* + * Bits 0 - 6 of the relocation are encoded into the + * 7bit unsigned immediate fields of the DESTINATION + * field of the instruction. The immediate value is + * left shifted by (0, 1, 2) based on the operand size. + */ + u32_t mask = (0x1f | (0x3 << 8)) << 16; + u32_t bottom, top; + val &= 0x7f; + if (reloc_type == R_UBICOM32_LO7_2_D) { + val >>= 1; + } else if (reloc_type == R_UBICOM32_LO7_4_D) { + val >>= 2; + } + bottom = (val & 0x1f) << 16; + top = (val >> 5) << 16; + insn &= ~mask; + insn |= bottom; + insn |= (top << 8); + BUG_ON(*rp != insn); + *rp = insn; + break; + } + case R_UBICOM32_LO7_CALLI: + case R_UBICOM32_LO16_CALLI: + { + /* + * Extract the offset for a CALLI instruction. The + * offsets can be either 7 bits or 18 bits. Since all + * instructions in ubicom32 architecture are at work + * aligned addresses the truncated offset is right + * shifted by 2 before being encoded in the instruction. + */ + if (reloc_type == R_UBICOM32_LO7_CALLI) { + val &= 0x7f; + } else { + val &= 0x3ffff; + } + + val >>= 2; + + insn &= ~0x071f071f; + insn |= (val & 0x1f) << 0; + val >>= 5; + insn |= (val & 0x07) << 8; + val >>= 3; + insn |= (val & 0x1f) << 16; + val >>= 5; + insn |= (val & 0x07) << 24; + if (reloc_type == R_UBICOM32_LO7_CALLI) { + BUG_ON(*rp != insn); + } + *rp = insn; + } + break; + } + + if (*persistent) { + *persistent = 0; + } +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S new file mode 100644 index 000000000..0c60504af --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S @@ -0,0 +1,273 @@ +/* + * arch/ubicom32/kernel/head.S + * + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#define __ASM__ +#include + + +#define SRC_AN A3 +#define DST_AN A4 + +#define PARAM_DN D0 +#define TMP_DN D15 +#define TMP2_DN D14 + +/* + * The following code is placed at the start of the Linux section of memory. + * This is the primary entry point for Linux. + * + * However, we also want the syscall entry/exit code to be at a fixed address. + * So we take the primary entry point and reserve 16 bytes. That address is + * where the system_call entry point exists. This 16 bytes basically allows + * us to jump around the system_call entry point code to the actual startup + * code. + * + * Linux Memory Map (see vlinux.lds.S): + * 0x40400000 - Primary Entry Point for Linux (jump around code below). + * 0x40400010 - Old syscall Entry Point. + */ + + .sect .skip_syscall, "ax", @progbits + .global __skip_syscall_section +__skip_syscall_section: + moveai A3, #%hi(_start) + lea.1 A3, %lo(_start)(A3) + ret A3 +/* + * __os_node_offset contains the offset from KERNELBASE to the os_node, it is + * not intended to be used by anything except the boot code. + */ +__os_node_offset: +.long (_os_node - KERNELSTART) + +.text +.global _start + +/* + * start() + * This is the start of the Linux kernel. + */ +_start: + move.4 SCRATCHPAD1, #0 + + +/* + * Setup the range registers... the loader has setup a few, but we will go ahead + * and correct them for our own limits. Note that once set these are never + * changed again. The ranges are as follows + * + * D_RANGE0 - io block (set up by loaded) + * + * I_RANGE0 and D_RANGE1 - kernel/ultra loader address space bottom of ocm-> top + * of ram typically 0x3ffc0000 - 0x440000000 + * I_RANGE1 - kernel / userspace transition area (aka syscalls, context switches) + * typically 0x3FFC0030 - ~0x3FFC0200 + * I_RANGE2 / D_RANGE2 - slab area + * typically 0x40A00000 - ~0x44000000 + * I_RANGE3 + * old system call interface if enabled. + * + * D_RANGE3, D_RANGE4 - unused. + */ + moveai SRC_AN, #%hi(PAGE_OFFSET_RAW) + lea.4 SRC_AN, %lo(PAGE_OFFSET_RAW)(SRC_AN) + move.4 D_RANGE1_LO, SRC_AN + move.4 I_RANGE0_LO, SRC_AN + +; don't try to calculate I_RANGE_HI, see below +; moveai SRC_AN, #%hi(___init_end-4) +; lea.4 SRC_AN, %lo(___init_end-4)(SRC_AN) +; move.4 I_RANGE0_HI, SRC_AN + + moveai SRC_AN, #%hi(SDRAMSTART + CONFIG_MIN_RAMSIZE-4) + lea.4 SRC_AN, %lo(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)(SRC_AN) + move.4 D_RANGE1_HI, SRC_AN + +; for now allow the whole ram to be executable as well so we don't run into problems +; once we load user more code. + move.4 I_RANGE0_HI, SRC_AN + +#ifdef CONFIG_PROTECT_KERNEL +; when kernel protection is enabled, we only open up syscall and non kernel text +; for userspace apps, for now only irange registers registers 1 and 2 are used for userspace. + + ;; syscall range + moveai SRC_AN, #%hi(__syscall_text_run_begin) + lea.4 SRC_AN, %lo(__syscall_text_run_begin)(SRC_AN) + move.4 I_RANGE1_LO, SRC_AN + moveai SRC_AN, #%hi(__syscall_text_run_end) + lea.4 SRC_AN, %lo(__syscall_text_run_end)(SRC_AN) + move.4 I_RANGE1_HI, SRC_AN + + ;; slab instructions + moveai SRC_AN, #%hi(_edata) + lea.4 SRC_AN, %lo(_edata)(SRC_AN) + move.4 I_RANGE2_LO, SRC_AN + ;; End of DDR is already in range0 hi so just copy it. + move.4 I_RANGE2_HI, I_RANGE0_HI + +#ifdef CONFIG_OLD_40400010_SYSTEM_CALL + ;; create a small hole for old syscall location + moveai SRC_AN, #%hi(0x40400000) + lea.4 I_RANGE3_LO, 0x10(SRC_AN) + lea.4 I_RANGE3_HI, 0x14(SRC_AN) +#endif + ;; slab data (same as slab instructions but starting a little earlier). + moveai SRC_AN, #%hi(_data_protection_end) + lea.4 SRC_AN, %lo(_data_protection_end)(SRC_AN) + move.4 D_RANGE2_LO, SRC_AN + move.4 D_RANGE2_HI, I_RANGE0_HI + +;; enable ranges + ;; skip I_RANGE0_EN + move.4 I_RANGE1_EN, #-1 + move.4 I_RANGE2_EN, #-1 +#ifdef CONFIG_OLD_40400010_SYSTEM_CALL + move.4 I_RANGE3_EN, #-1 +#else + move.4 I_RANGE3_EN, #0 +#endif + ;; skip D_RANGE0_EN or D_RANGE1_EN + move.4 D_RANGE2_EN, #-1 + move.4 D_RANGE3_EN, #0 + move.4 D_RANGE4_EN, #0 +#endif + +; +; If __ocm_free_begin is smaller than __ocm_free_end the +; setup OCM text and data ram banks properly +; + moveai DST_AN, #%hi(__ocm_free_begin) + lea.4 TMP_DN, %lo(__ocm_free_begin)(DST_AN) + moveai DST_AN, #%hi(__ocm_free_end) + lea.4 TMP2_DN, %lo(__ocm_free_end)(DST_AN) + sub.4 #0, TMP2_DN, TMP_DN + jmple.f 2f + moveai DST_AN, #%hi(__data_begin) + lea.4 TMP_DN, %lo(__data_begin)(DST_AN) + moveai DST_AN, #%hi(OCMSTART) + lea.4 TMP2_DN, %lo(OCMSTART)(DST_AN) + sub.4 TMP_DN, TMP_DN, TMP2_DN + lsr.4 TMP_DN, TMP_DN, #15 + lsl.4 TMP_DN, #1, TMP_DN + moveai DST_AN, #%hi(OCMC_BASE) + add.4 OCMC_BANK_MASK(DST_AN), #-1, TMP_DN + pipe_flush 0 +2: +; +; Load .ocm_text +; + moveai DST_AN, #%hi(__ocm_text_run_end) + lea.4 TMP_DN, %lo(__ocm_text_run_end)(DST_AN) + moveai DST_AN, #%hi(__ocm_text_run_begin) + lea.4 DST_AN, %lo(__ocm_text_run_begin)(DST_AN) + moveai SRC_AN, #%hi(__ocm_text_load_begin) + lea.4 SRC_AN, %lo(__ocm_text_load_begin)(SRC_AN) + jmpt.t 2f + +1: move.4 (DST_AN)4++, (SRC_AN)4++ + +2: sub.4 #0, DST_AN, TMP_DN + jmpne.t 1b +; +; Load .syscall_text +; + moveai DST_AN, #%hi(__syscall_text_run_end) + lea.4 TMP_DN, %lo(__syscall_text_run_end)(DST_AN) + moveai DST_AN, #%hi(__syscall_text_run_begin) + lea.4 DST_AN, %lo(__syscall_text_run_begin)(DST_AN) + moveai SRC_AN, #%hi(__syscall_text_load_begin) + lea.4 SRC_AN, %lo(__syscall_text_load_begin)(SRC_AN) + jmpt.t 2f + +1: move.4 (DST_AN)4++, (SRC_AN)4++ + +2: sub.4 #0, DST_AN, TMP_DN + jmpne.t 1b + +; +; Load .ocm_data +; + moveai DST_AN, #%hi(__ocm_data_run_end) + lea.4 TMP_DN, %lo(__ocm_data_run_end)(DST_AN) + moveai DST_AN, #%hi(__ocm_data_run_begin) + lea.4 DST_AN, %lo(__ocm_data_run_begin)(DST_AN) + moveai SRC_AN, #%hi(__ocm_data_load_begin) + lea.4 SRC_AN, %lo(__ocm_data_load_begin)(SRC_AN) + jmpt.t 2f + +1: move.4 (DST_AN)4++, (SRC_AN)4++ + +2: sub.4 #0, DST_AN, TMP_DN + jmpne.t 1b + +; Clear .bss +; + moveai SRC_AN, #%hi(_ebss) + lea.4 TMP_DN, %lo(_ebss)(SRC_AN) + moveai DST_AN, #%hi(_sbss) + lea.4 DST_AN, %lo(_sbss)(DST_AN) + jmpt.t 2f + +1: move.4 (DST_AN)4++, #0 + +2: sub.4 #0, DST_AN, TMP_DN + jmpne.t 1b + +; save our parameter to devtree (after clearing .bss) + moveai DST_AN, #%hi(devtree) + lea.4 DST_AN, %lo(devtree)(DST_AN) + move.4 (DST_AN), PARAM_DN + + moveai sp, #%hi(init_thread_union) + lea.4 sp, %lo(init_thread_union)(sp) + movei TMP_DN, #ASM_THREAD_SIZE + add.4 sp, sp, TMP_DN + move.4 -4(sp)++, #0 ; nesting level = 0 + move.4 -4(sp)++, #1 ; KERNEL_THREAD + +;; ip3k-elf-gdb backend now sets scratchpad3 to 1 when either continue +;; or single step commands are issued. scratchpad3 is set to 0 when the +;; debugger detaches from the board. + move.4 TMP_DN, scratchpad3 + lsl.4 TMP_DN, TMP_DN, #0x0 + jmpeq.f _jump_to_start_kernel +_ok_to_set_break_points_in_linux: +;; THREAD_STALL + move.4 mt_dbg_active_clr,#-1 +;; stalling the threads isn't instantaneous.. need to flush the pipe. + pipe_flush 0 + pipe_flush 0 + +_jump_to_start_kernel: + moveai SRC_AN, #%hi(start_kernel) + lea.4 SRC_AN, %lo(start_kernel)(SRC_AN) + ret SRC_AN diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/init_task.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/init_task.c new file mode 100644 index 000000000..58baf5270 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/init_task.c @@ -0,0 +1,65 @@ +/* + * arch/ubicom32/kernel/init_task.c + * Ubicom32 architecture task initialization implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///static struct fs_struct init_fs = INIT_FS; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) +struct mm_struct init_mm = INIT_MM(init_mm); +EXPORT_SYMBOL(init_mm); +#endif + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); + +EXPORT_SYMBOL(init_task); + +/* + * Initial thread structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c new file mode 100644 index 000000000..c041f23e2 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c @@ -0,0 +1,597 @@ +/* + * arch/ubicom32/kernel/irq.c + * Ubicom32 architecture IRQ support. + * + * (C) Copyright 2009, Ubicom, Inc. + * (C) Copyright 2007, Greg Ungerer + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned int irq_soft_avail; +static struct irqaction ubicom32_reserve_action[NR_IRQS]; + +#if !defined(CONFIG_DEBUG_IRQMEASURE) +#define IRQ_DECLARE_MEASUREMENT +#define IRQ_MEASUREMENT_START() +#define IRQ_MEASUREMENT_END(irq) +#else +#define IRQ_DECLARE_MEASUREMENT \ + int __diff; \ + unsigned int __tstart; + +#define IRQ_MEASUREMENT_START() \ + __tstart = UBICOM32_IO_TIMER->sysval; + +#define IRQ_MEASUREMENT_END(irq) \ + __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \ + irq_measurement_update((irq), __diff); + +/* + * We keep track of the time spent in both irq_enter() + * and irq_exit(). + */ +#define IRQ_WEIGHT 32 + +struct irq_measurement { + volatile unsigned int min; + volatile unsigned int avg; + volatile unsigned int max; +}; + +static DEFINE_SPINLOCK(irq_measurement_lock); + +/* + * Add 1 in for softirq (irq_exit()); + */ +static struct irq_measurement irq_measurements[NR_IRQS + 1]; + +/* + * irq_measurement_update() + * Update an entry in the measurement array for this irq. + */ +static void irq_measurement_update(int irq, int sample) +{ + struct irq_measurement *im = &irq_measurements[irq]; + spin_lock(&irq_measurement_lock); + if ((im->min == 0) || (im->min > sample)) { + im->min = sample; + } + if (im->max < sample) { + im->max = sample; + } + im->avg = ((im->avg * (IRQ_WEIGHT - 1)) + sample) / IRQ_WEIGHT; + spin_unlock(&irq_measurement_lock); +} +#endif + +/* + * irq_kernel_stack_check() + * See if the kernel stack is within STACK_WARN of the end. + */ +static void irq_kernel_stack_check(int irq, struct pt_regs *regs) +{ +#ifdef CONFIG_DEBUG_STACKOVERFLOW + unsigned long sp; + + /* + * Make sure that we are not close to the top of the stack and thus + * can not really service this interrupt. + */ + asm volatile ( + "and.4 %0, SP, %1 \n\t" + : "=d" (sp) + : "d" (THREAD_SIZE - 1) + : "cc" + ); + + if (sp < (sizeof(struct thread_info) + STACK_WARN)) { + printk(KERN_WARNING + "cpu[%d]: possible overflow detected sp remain: %p, " + "irq: %d, regs: %p\n", + thread_get_self(), (void *)sp, irq, regs); + dump_stack(); + } + + if (sp < (sizeof(struct thread_info) + 16)) { + THREAD_STALL; + } +#endif +} + +/* + * irq_get_lsb() + * Get the LSB set in value + */ +static int irq_get_lsb(unsigned int value) +{ + static unsigned char irq_bits[8] = { + 3, 0, 1, 0, 2, 0, 1, 0 + }; + u32_t nextbit = 0; + + value = (value >> nextbit) | (value << ((sizeof(value) * 8) - nextbit)); + + /* + * It's unlikely that we find that we execute the body of this while + * loop. 50% of the time we won't take this at all and then of the + * cases where we do about 50% of those we only execute once. + */ + if (!(value & 0xffff)) { + nextbit += 0x10; + value >>= 16; + } + + if (!(value & 0xff)) { + nextbit += 0x08; + value >>= 8; + } + + if (!(value & 0xf)) { + nextbit += 0x04; + value >>= 4; + } + + nextbit += irq_bits[value & 0x7]; + if (nextbit > 63) { + panic("nextbit out of range: %d\n", nextbit); + } + return nextbit; +} + +/* + * ubicom32_reserve_handler() + * Bogus handler associated with pre-reserved IRQ(s). + */ +static irqreturn_t ubicom32_reserve_handler(int irq, void *dev_id) +{ + BUG(); + return IRQ_HANDLED; +} + +/* + * __irq_disable_vector() + * Disable the interrupt by clearing the appropriate bit in the + * LDSR Mask Register. + */ +static void __irq_disable_vector(unsigned int irq) +{ + ldsr_disable_vector(irq); +} + +/* + * __irq_ack_vector() + * Acknowledge the specific interrupt by clearing the associate bit in + * hardware + */ +static void __irq_ack_vector(unsigned int irq) +{ + if (irq < 32) { + asm volatile ("move.4 INT_CLR0, %0" : : "d" (1 << irq)); + } else { + asm volatile ("move.4 INT_CLR1, %0" : : "d" (1 << (irq - 32))); + } +} + +/* + * __irq_enable_vector() + * Clean and then enable the interrupt by setting the appropriate bit in + * the LDSR Mask Register. + */ +static void __irq_enable_vector(unsigned int irq) +{ + /* + * Acknowledge, really clear the vector. + */ + __irq_ack_vector(irq); + ldsr_enable_vector(irq); +} + +/* + * __irq_mask_vector() + */ +static void __irq_mask_vector(unsigned int irq) +{ + ldsr_mask_vector(irq); +} + +/* + * __irq_unmask_vector() + */ +static void __irq_unmask_vector(unsigned int irq) +{ + ldsr_unmask_vector(irq); +} + +/* + * __irq_end_vector() + * Called once an interrupt is completed (reset the LDSR mask). + */ +static void __irq_end_vector(unsigned int irq) +{ + ldsr_unmask_vector(irq); +} + +#if defined(CONFIG_SMP) +/* + * __irq_set_affinity() + * Set the cpu affinity for this interrupt. + * affinity container allocated at boot + */ +static void __irq_set_affinity(unsigned int irq, const struct cpumask *dest) +{ + smp_set_affinity(irq, dest); + cpumask_copy(irq_desc[irq].affinity, dest); +} +#endif + +/* + * On-Chip Generic Interrupt function handling. + */ +static struct irq_chip ubicom32_irq_chip = { + .name = "Ubicom32", + .startup = NULL, + .shutdown = NULL, + .enable = __irq_enable_vector, + .disable = __irq_disable_vector, + .ack = __irq_ack_vector, + .mask = __irq_mask_vector, + .unmask = __irq_unmask_vector, + .end = __irq_end_vector, +#if defined(CONFIG_SMP) + .set_affinity = __irq_set_affinity, +#endif +}; + +/* + * do_IRQ() + * Primary interface for handling IRQ() requests. + */ +asmlinkage void do_IRQ(int irq, struct pt_regs *regs) +{ + struct pt_regs *oldregs; + struct thread_info *ti = current_thread_info(); + + IRQ_DECLARE_MEASUREMENT; + + /* + * Mark that we are inside of an interrupt and + * that interrupts are disabled. + */ + oldregs = set_irq_regs(regs); + ti->interrupt_nesting++; + trace_hardirqs_off(); + irq_kernel_stack_check(irq, regs); + + /* + * Start the interrupt sequence + */ + irq_enter(); + + /* + * Execute the IRQ handler and any pending SoftIRQ requests. + */ + BUG_ON(!irqs_disabled()); + IRQ_MEASUREMENT_START(); + __do_IRQ(irq); + IRQ_MEASUREMENT_END(irq); + BUG_ON(!irqs_disabled()); + + /* + * TODO: Since IRQ's are disabled when calling irq_exit() + * modify Kconfig to set __ARCH_IRQ_EXIT_IRQS_DISABLED flag. + * This will slightly improve performance by enabling + * softirq handling to avoid disabling/disabled interrupts. + */ + IRQ_MEASUREMENT_START(); + irq_exit(); + IRQ_MEASUREMENT_END(NR_IRQS); + BUG_ON(!irqs_disabled()); + + /* + * Outside of an interrupt (or nested exit). + */ + set_irq_regs(oldregs); + trace_hardirqs_on(); + ti->interrupt_nesting--; +} + +/* + * irq_soft_alloc() + * Allocate a soft IRQ. + */ +int irq_soft_alloc(unsigned int *soft) +{ + if (irq_soft_avail == 0) { + printk(KERN_NOTICE "no soft irqs to allocate\n"); + return -EFAULT; + } + + *soft = irq_get_lsb(irq_soft_avail); + irq_soft_avail &= ~(1 << *soft); + return 0; +} + +/* + * ack_bad_irq() + * Called to handle an bad irq request. + */ +void ack_bad_irq(unsigned int irq) +{ + printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq); + __irq_end_vector(irq); +} + +/* + * show_interrupts() + * Return a string that displays the state of each of the interrupts. + */ +int show_interrupts(struct seq_file *p, void *v) +{ + struct irqaction *ap; + int irq = *((loff_t *) v); + int j; + + if (irq >= NR_IRQS) { + return 0; + } + + if (irq == 0) { + seq_puts(p, " "); + for_each_online_cpu(j) { + seq_printf(p, "CPU%d ", j); + } + seq_putc(p, '\n'); + } + + ap = irq_desc[irq].action; + if (ap) { + seq_printf(p, "%3d: ", irq); + for_each_online_cpu(j) { + seq_printf(p, "%10u ", kstat_irqs_cpu(irq, j)); + } + seq_printf(p, "%14s ", irq_desc[irq].chip->name); + seq_printf(p, "%s", ap->name); + for (ap = ap->next; ap; ap = ap->next) { + seq_printf(p, ", %s", ap->name); + } + seq_putc(p, '\n'); + } + return 0; +} + +#if defined(CONFIG_DEBUG_IRQMEASURE) +static unsigned int irq_cycles_to_micro(unsigned int cycles, unsigned int frequency) +{ + unsigned int micro = (cycles / (frequency / 1000000)); + return micro; +} + +/* + * irq_measurement_show() + * Print out the min, avg, max values for each IRQ + * + * By request, the max value is reset after each dump. + */ +static int irq_measurement_show(struct seq_file *p, void *v) +{ + struct irqaction *ap; + unsigned int freq = processor_frequency(); + int irq = *((loff_t *) v); + + + if (irq == 0) { + seq_puts(p, "\tmin\tavg\tmax\t(micro-seconds)\n"); + } + + if (irq > NR_IRQS) { + return 0; + } + + if (irq == NR_IRQS) { + unsigned int min, avg, max; + spin_lock(&irq_measurement_lock); + min = irq_cycles_to_micro(irq_measurements[irq].min, freq); + avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq); + max = irq_cycles_to_micro(irq_measurements[irq].max, freq); + irq_measurements[irq].max = 0; + spin_unlock(&irq_measurement_lock); + seq_printf(p, " \t%u\t%u\t%u\tsoftirq\n", min, avg, max); + return 0; + } + + ap = irq_desc[irq].action; + if (ap) { + unsigned int min, avg, max; + spin_lock(&irq_measurement_lock); + min = irq_cycles_to_micro(irq_measurements[irq].min, freq); + avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq); + max = irq_cycles_to_micro(irq_measurements[irq].max, freq); + irq_measurements[irq].max = 0; + spin_unlock(&irq_measurement_lock); + seq_printf(p, "%2u:\t%u\t%u\t%u\t%s\n", irq, min, avg, max, ap->name); + } + return 0; +} + +static void *irq_measurement_start(struct seq_file *f, loff_t *pos) +{ + return (*pos <= NR_IRQS) ? pos : NULL; +} + +static void *irq_measurement_next(struct seq_file *f, void *v, loff_t *pos) +{ + (*pos)++; + if (*pos > NR_IRQS) + return NULL; + return pos; +} + +static void irq_measurement_stop(struct seq_file *f, void *v) +{ + /* Nothing to do */ +} + +static const struct seq_operations irq_measurement_seq_ops = { + .start = irq_measurement_start, + .next = irq_measurement_next, + .stop = irq_measurement_stop, + .show = irq_measurement_show, +}; + +static int irq_measurement_open(struct inode *inode, struct file *filp) +{ + return seq_open(filp, &irq_measurement_seq_ops); +} + +static const struct file_operations irq_measurement_fops = { + .open = irq_measurement_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init irq_measurement_init(void) +{ + proc_create("irq_measurements", 0, NULL, &irq_measurement_fops); + return 0; +} +module_init(irq_measurement_init); +#endif + +/* + * init_IRQ(void) + * Initialize the on-chip IRQ subsystem. + */ +void __init init_IRQ(void) +{ + int irq; + struct devtree_node *p = NULL; + struct devtree_node *iter = NULL; + unsigned int mask = 0; + unsigned int reserved = 0; + + /* + * Pull out the list of software interrupts that are avialable to + * Linux and provide an allocation function for them. The first + * 24 interrupts of INT0 are software interrupts. + */ + irq_soft_avail = 0; + if (processor_interrupts(&irq_soft_avail, NULL) < 0) { + printk(KERN_WARNING "No Soft IRQ(s) available\n"); + } + irq_soft_avail &= ((1 << 24) - 1); + + /* + * Initialize all of the on-chip interrupt handling + * to use a common set of interrupt functions. + */ + for (irq = 0; irq < NR_IRQS; irq++) { + irq_desc[irq].status = IRQ_DISABLED; + irq_desc[irq].action = NULL; + irq_desc[irq].depth = 1; + set_irq_chip(irq, &ubicom32_irq_chip); + } + + /* + * The sendirq of a devnode is not registered within Linux but instead + * is used by the software I/O thread. These interrupts are reserved. + * The recvirq is used by Linux and registered by a device driver, these + * are not reserved. + * + * recvirq(s) that are in the software interrupt range are not supposed + * to be marked as reserved. We track this while we scan the device + * nodes. + */ + p = devtree_find_next(&iter); + while (p) { + unsigned char sendirq, recvirq; + devtree_irq(p, &sendirq, &recvirq); + + /* + * If the sendirq is valid, mark that irq as taken by the + * devtree node. + */ + if (sendirq < NR_IRQS) { + ubicom32_reserve_action[sendirq].handler = + ubicom32_reserve_handler; + ubicom32_reserve_action[sendirq].name = p->name; + irq_desc[sendirq].action = + &ubicom32_reserve_action[sendirq]; + mask |= (1 << sendirq); + } + + /* + * Track the relevant recieve IRQ(s) + */ + if (recvirq < 24) { + mask |= (1 << recvirq); + } + + /* + * Move to the next node. + */ + p = devtree_find_next(&iter); + } + + /* + * Remove these bits from the irq_soft_avail list and then use the + * result as the list of pre-reserved IRQ(s). + */ + reserved = ~irq_soft_avail & ~mask; + for (irq = 0; irq < 24; irq++) { + if ((reserved & (1 << irq))) { + ubicom32_reserve_action[irq].handler = + ubicom32_reserve_handler; + ubicom32_reserve_action[irq].name = "reserved"; + irq_desc[irq].action = &ubicom32_reserve_action[irq]; + } + } + + /* + * Initialize the LDSR which is the Ubicom32 programmable + * interrupt controller. + */ + ldsr_init(); + + /* + * The Ubicom trap code needs a 2nd init after IRQ(s) are setup. + */ + trap_init_interrupt(); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ldsr.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/ldsr.c new file mode 100644 index 000000000..a608d74cf --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/ldsr.c @@ -0,0 +1,1185 @@ +/* + * arch/ubicom32/kernel/ldsr.c + * Ubicom32 architecture Linux Device Services Driver Interface + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * + * NOTES: + * + * The LDSR is a programmable interrupt controller that is written in software. + * It emulates the behavior of an pic by fielding the interrupts, choosing a + * victim thread to take the interrupt and forcing that thread to take a context + * switch to the appropriate interrupt handler. + * + * Because traps are treated as just a special class of interrupts, the LDSR + * also handles the processing of traps. + * + * Because we compile Linux both UP and SMP, we need the LDSR to use + * architectural locking that is not "compiled out" when compiling UP. For now, + * we use the single atomic bit lock. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * One can not print from the LDSR so the best we can do is + * check a condition and stall all of the threads. + */ + +// #define DEBUG_LDSR 1 +#if defined(DEBUG_LDSR) +#define DEBUG_ASSERT(cond) \ + if (!(cond)) { \ + THREAD_STALL; \ + } +#else +#define DEBUG_ASSERT(cond) +#endif + +/* + * Make global so that we can use it in the RFI code in assembly. + */ +unsigned int ldsr_soft_irq_mask; +EXPORT_SYMBOL(ldsr_soft_irq_mask); + +static unsigned int ldsr_suspend_mask; +static unsigned int ldsr_soft_irq; +static unsigned int ldsr_stack_space[1024]; + +static struct ldsr_register_bank { + volatile unsigned int enabled0; + volatile unsigned int enabled1; + volatile unsigned int mask0; + volatile unsigned int mask1; + unsigned int total; + unsigned int retry; + unsigned int backout; +} ldsr_interrupt; + +/* + * Which thread/cpu are we? + */ +static int ldsr_tid = -1; + +#if defined(CONFIG_IRQSTACKS) +/* + * per-CPU IRQ stacks (thread information and stack) + * + * NOTE: Do not use DEFINE_PER_CPU() as it makes it harder + * to find the location of ctx from assembly language. + */ +union irq_ctx { + struct thread_info tinfo; + u32 stack[THREAD_SIZE/sizeof(u32)]; +}; +static union irq_ctx *percpu_irq_ctxs[NR_CPUS]; + +/* + * Storage for the interrupt stack. + */ +#if !defined(CONFIG_IRQSTACKS_USEOCM) +static char percpu_irq_stacks[(NR_CPUS * THREAD_SIZE) + (THREAD_SIZE - 1)]; +#else +/* + * For OCM, the linker will ensure that space is allocated for the stack + * see (vmlinux.lds.S) + */ +static char percpu_irq_stacks[]; +#endif + +#endif + +/* + * Save trap IRQ because we need to un-suspend if it gets set. + */ +static unsigned int ldsr_trap_irq_mask; +static unsigned int ldsr_trap_irq; + +/* + * ret_from_interrupt_to_kernel + * Just restore the context and do nothing else. + */ +asmlinkage void ret_from_interrupt_to_kernel(void)__attribute__((naked)); + +/* + * ret_from_interrupt_to_user + * Call scheduler if needed. Just restore the context. + */ +asmlinkage void ret_from_interrupt_to_user(void)__attribute__((naked)); + +#ifdef DEBUG_LDSR +u32_t old_sp, old_pc, old_a0, old_a5, old_a3; +struct pt_regs copy_regs, *copy_save_area; +#endif + +int __user_mode(unsigned long sp) +{ + + u32_t saved_stack_base = sp & ~(ASM_THREAD_SIZE - 1); +#if defined(CONFIG_IRQSTACKS_USEOCM) + if ((union irq_ctx *)saved_stack_base == percpu_irq_ctxs[smp_processor_id()]) { + /* + * On the interrupt stack. + */ + return 0; + } +#endif + + if (!(u32_t)current) { + return 0; + } + return saved_stack_base != ((u32_t)current->stack); +} + +/* + * ldsr_lock_release() + * Release the LDSR lock. + */ +static void ldsr_lock_release(void) +{ + UBICOM32_UNLOCK(LDSR_LOCK_BIT); +} + +/* + * ldsr_lock_acquire() + * Acquire the LDSR lock, spin if not available. + */ +static void ldsr_lock_acquire(void) +{ + UBICOM32_LOCK(LDSR_LOCK_BIT); +} + +/* + * ldsr_thread_irq_disable() + * Disable interrupts for the specified thread. + */ +static void ldsr_thread_irq_disable(unsigned int tid) +{ + unsigned int mask = (1 << tid); + + asm volatile ( + " or.4 scratchpad1, scratchpad1, %0 \n\t" + : + : "d"(mask) + : "cc" + ); +} + +/* + * ldsr_thread_get_interrupts() + * Get the interrupt state for all threads. + */ +static unsigned long ldsr_thread_get_interrupts(void) +{ + unsigned long ret = 0; + asm volatile ( + " move.4 %0, scratchpad1 \n\t" + : "=r" (ret) + : + ); + return ret; +} + +/* + * ldsr_emulate_and_run() + * Emulate the instruction and then set the thread to run. + */ +static void ldsr_emulate_and_run(unsigned int tid) +{ + unsigned int thread_mask = (1 << tid); + u32_t write_csr = (tid << 15) | (1 << 14); + + /* + * Emulate the unaligned access. + */ + unaligned_emulate(tid); + + /* + * Get the thread back in a running state. + */ + asm volatile ( + " setcsr %0 \n\t" + " setcsr_flush 0 \n\t" + " move.4 trap_cause, #0 \n\t" /* Clear the trap cause + * register */ + " setcsr #0 \n\t" + " setcsr_flush 0 \n\t" + " move.4 mt_dbg_active_set, %1 \n\t" /* Activate thread even if + * in dbg/fault state */ + " move.4 mt_active_set, %1 \n\t" /* Restart target + * thread. */ + : + : "r" (write_csr), "d" (thread_mask) + : "cc" + ); + thread_enable_mask(thread_mask); +} + +/* + * ldsr_preemptive_context_save() + * save thread context from another hardware thread. The other thread must + * be stalled. + */ +static inline void ldsr_preemptive_context_save(u32_t thread, + struct pt_regs *regs) +{ + /* + * Save the current state of the specified thread + */ + asm volatile ( + " move.4 a3, %0 \n\t" + + /* set src1 from the target thread */ + " move.4 csr, %1 \n\t" + " setcsr_flush 0 \n\t" + " setcsr_flush 0 \n\t" + + /* copy state from the other thread */ + " move.4 "D(PT_D0)"(a3), d0 \n\t" + " move.4 "D(PT_D1)"(a3), d1 \n\t" + " move.4 "D(PT_D2)"(a3), d2 \n\t" + " move.4 "D(PT_D3)"(a3), d3 \n\t" + " move.4 "D(PT_D4)"(a3), d4 \n\t" + " move.4 "D(PT_D5)"(a3), d5 \n\t" + " move.4 "D(PT_D6)"(a3), d6 \n\t" + " move.4 "D(PT_D7)"(a3), d7 \n\t" + " move.4 "D(PT_D8)"(a3), d8 \n\t" + " move.4 "D(PT_D9)"(a3), d9 \n\t" + " move.4 "D(PT_D10)"(a3), d10 \n\t" + " move.4 "D(PT_D11)"(a3), d11 \n\t" + " move.4 "D(PT_D12)"(a3), d12 \n\t" + " move.4 "D(PT_D13)"(a3), d13 \n\t" + " move.4 "D(PT_D14)"(a3), d14 \n\t" + " move.4 "D(PT_D15)"(a3), d15 \n\t" + " move.4 "D(PT_A0)"(a3), a0 \n\t" + " move.4 "D(PT_A1)"(a3), a1 \n\t" + " move.4 "D(PT_A2)"(a3), a2 \n\t" + " move.4 "D(PT_A3)"(a3), a3 \n\t" + " move.4 "D(PT_A4)"(a3), a4 \n\t" + " move.4 "D(PT_A5)"(a3), a5 \n\t" + " move.4 "D(PT_A6)"(a3), a6 \n\t" + " move.4 "D(PT_SP)"(a3), a7 \n\t" + " move.4 "D(PT_ACC0HI)"(a3), acc0_hi \n\t" + " move.4 "D(PT_ACC0LO)"(a3), acc0_lo \n\t" + " move.4 "D(PT_MAC_RC16)"(a3), mac_rc16 \n\t" + " move.4 "D(PT_ACC1HI)"(a3), acc1_hi \n\t" + " move.4 "D(PT_ACC1LO)"(a3), acc1_lo \n\t" + " move.4 "D(PT_SOURCE3)"(a3), source3 \n\t" + " move.4 "D(PT_INST_CNT)"(a3), inst_cnt \n\t" + " move.4 "D(PT_CSR)"(a3), csr \n\t" + " move.4 "D(PT_DUMMY_UNUSED)"(a3), #0 \n\t" + " move.4 "D(PT_INT_MASK0)"(a3), int_mask0 \n\t" + " move.4 "D(PT_INT_MASK1)"(a3), int_mask1 \n\t" + " move.4 "D(PT_TRAP_CAUSE)"(a3), trap_cause \n\t" + " move.4 "D(PT_PC)"(a3), pc \n\t" + " move.4 "D(PT_PREVIOUS_PC)"(a3), previous_pc \n\t" + /* disable csr thread select */ + " movei csr, #0 \n\t" + " setcsr_flush 0 \n\t" + : + : "r" (regs->dn), "d" ((thread << 9) | (1 << 8)) + : "a3" + ); +} + +/* + * ldsr_rotate_threads() + * Simple round robin algorithm for choosing the next cpu + */ +static int ldsr_rotate_threads(unsigned long cpus) +{ + static unsigned char ldsr_bits[8] = { + 3, 0, 1, 0, 2, 0, 1, 0 + }; + + static int nextbit; + int thisbit; + + /* + * Move the interrupts down so that we consider interrupts from where + * we left off, then take the interrupts we would lose and move them + * to the top half of the interrupts value. + */ + cpus = (cpus >> nextbit) | (cpus << ((sizeof(cpus) * 8) - nextbit)); + + /* + * 50% of the time we won't take this at all and then of the cases where + * we do about 50% of those we only execute once. + */ + if (!(cpus & 0xffff)) { + nextbit += 16; + cpus >>= 16; + } + + if (!(cpus & 0xff)) { + nextbit += 8; + cpus >>= 8; + } + + if (!(cpus & 0xf)) { + nextbit += 4; + cpus >>= 4; + } + + nextbit += ldsr_bits[cpus & 0x7]; + thisbit = (nextbit & ((sizeof(cpus) * 8) - 1)); + nextbit = (thisbit + 1) & ((sizeof(cpus) * 8) - 1); + DEBUG_ASSERT(thisbit < THREAD_ARCHITECTURAL_MAX); + return thisbit; +} + +/* + * ldsr_rotate_interrupts() + * Get rotating next set bit value. + */ +static int ldsr_rotate_interrupts(unsigned long long interrupts) +{ + static unsigned char ldsr_bits[8] = { + 3, 0, 1, 0, 2, 0, 1, 0 + }; + + static int nextbit; + int thisbit; + + /* + * Move the interrupts down so that we consider interrupts from where + * we left off, then take the interrupts we would lose and move them + * to the top half of the interrupts value. + */ + interrupts = (interrupts >> nextbit) | + (interrupts << ((sizeof(interrupts) * 8) - nextbit)); + + /* + * 50% of the time we won't take this at all and then of the cases where + * we do about 50% of those we only execute once. + */ + if (!(interrupts & 0xffffffff)) { + nextbit += 32; + interrupts >>= 32; + } + + if (!(interrupts & 0xffff)) { + nextbit += 16; + interrupts >>= 16; + } + + if (!(interrupts & 0xff)) { + nextbit += 8; + interrupts >>= 8; + } + + if (!(interrupts & 0xf)) { + nextbit += 4; + interrupts >>= 4; + } + + nextbit += ldsr_bits[interrupts & 0x7]; + thisbit = (nextbit & ((sizeof(interrupts) * 8) - 1)); + nextbit = (thisbit + 1) & ((sizeof(interrupts) * 8) - 1); + + DEBUG_ASSERT(thisbit < (sizeof(interrupts) * 8)); + return thisbit; +} + +/* + * ldsr_backout_or_irq() + * + * One way or the other this interrupt is not being + * processed, make sure that it is reset. We are + * not going to call irq_end_vector() so unmask the + * interrupt. + */ +static void ldsr_backout_of_irq(int vector, unsigned long tid_mask) +{ +#if defined(CONFIG_SMP) + if (unlikely(vector == smp_ipi_irq)) { + smp_reset_ipi(tid_mask); + } +#endif + ldsr_unmask_vector(vector); + ldsr_interrupt.backout++; +} + +#if defined(CONFIG_IRQSTACKS) +/* + * ldsr_choose_savearea_and_returnvec() + * Test our current state (user, kernel, interrupt) and set things up. + * + * This version of the function uses 3 stacks and nests interrupts + * on the interrupt stack. + */ +static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec) +{ + struct pt_regs *save_area; + u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1); + struct thread_info * ti= (struct thread_info *)sw_ksp[tid]; + +#if defined(CONFIG_SMP) + union irq_ctx *icp = percpu_irq_ctxs[tid]; +#else + union irq_ctx *icp = percpu_irq_ctxs[0]; +#endif + + if (masked_linux_sp == (u32_t)icp) { + /* + * Fault/Interrupt occurred while on the interrupt stack. + */ + save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8); + *pvec = (u32_t)(&ret_from_interrupt_to_kernel); + } else { + /* + * Fault/Interrupt occurred while on user/kernel stack. This is a new + * first use of the interrupt stack. + */ + save_area = (struct pt_regs *) ((char *)icp + sizeof(icp->stack) - sizeof(struct pt_regs) - 8); + if (masked_linux_sp == (u32_t)ti) { + *pvec = (u32_t)(&ret_from_interrupt_to_kernel); + } else { + *pvec = (u32_t)(&ret_from_interrupt_to_user); + } + + /* + * Because the softirq code will execute on the "interrupt" stack, we + * need to maintain the knowledge of what "task" was executing on the + * cpu. This is done by copying the thread_info->task from the cpu + * we are about to context switch into the interrupt contexts thread_info + * structure. + */ + icp->tinfo.task = ti->task; + icp->tinfo.preempt_count = + (icp->tinfo.preempt_count & ~SOFTIRQ_MASK) | + (ti->preempt_count & SOFTIRQ_MASK); + icp->tinfo.interrupt_nesting = 0; + } + save_area->nesting_level = icp->tinfo.interrupt_nesting; + return save_area; +} + +#else +/* + * ldsr_choose_savearea_and_returnvec() + * Test our current state (user, kernel, interrupt) and set things up. + * + * The version of the function uses just the user & kernel stack and + * nests interrupts on the existing kernel stack. + */ +static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec) +{ + struct pt_regs *save_area; + u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1); + struct thread_info *ti = (struct thread_info *)sw_ksp[tid]; + + if (masked_linux_sp == (u32_t)ti) { + /* + * Fault/Interrupt occurred while on the kernel stack. + */ + save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8); + *pvec = (u32_t) (&ret_from_interrupt_to_kernel); + } else { + /* + * Fault/Interrupt occurred while on user stack. + */ + ti->interrupt_nesting = 0; + save_area = (struct pt_regs *)((u32_t)ti + THREAD_SIZE - sizeof(struct pt_regs) - 8); + *pvec = (u32_t) (&ret_from_interrupt_to_user); + } + save_area->nesting_level = ti->interrupt_nesting; + return save_area; +} +#endif + +/* + * ldsr_ctxsw_thread() + * Context switch a mainline thread to execute do_IRQ() for the specified + * vector. + */ +static void ldsr_ctxsw_thread(int vector, thread_t tid) +{ + u32_t linux_sp; + u32_t return_vector; + struct pt_regs *save_area, *regs; + u32_t thread_mask = (1 << tid); + u32_t read_csr = ((tid << 9) | (1 << 8)); + u32_t write_csr = (tid << 15) | (1 << 14); + u32_t interrupt_vector = (u32_t)(&do_IRQ); + + unsigned int frame_type = UBICOM32_FRAME_TYPE_INTERRUPT; + + + DEBUG_ASSERT(!thread_is_enabled(tid)); + + /* + * Acquire the necessary global and per thread locks for tid. + * As a side effect, we ensure that the thread has not trapped + * and return true if it has. + */ + if (unlikely(thread_is_trapped(tid))) { + /* + * Read the trap cause, the sp and clear the MT_TRAP bits. + */ + unsigned int cause; + asm volatile ( + " setcsr %3 \n\t" + " setcsr_flush 0 \n\t" + " setcsr_flush 0 \n\t" + " move.4 %0, TRAP_CAUSE \n\t" + " move.4 %1, SP \n\t" + " setcsr #0 \n\t" + " setcsr_flush 0 \n\t" + " move.4 MT_BREAK_CLR, %2\n\t" + " move.4 MT_TRAP_CLR, %2 \n\t" + : "=&r" (cause), "=&r" (linux_sp) + : "r" (thread_mask), "m" (read_csr) + ); + + ldsr_backout_of_irq(vector, (1 << tid)); + +#if !defined(CONFIG_UNALIGNED_ACCESS_DISABLED) + /* + * See if the unaligned trap handler can deal with this. + * If so, emulate the instruction and then just restart + * the thread. + */ + if (unaligned_only(cause)) { +#if defined(CONFIG_UNALIGNED_ACCESS_USERSPACE_ONLY) + /* + * Check if this is a kernel stack if so we will not + * handle the trap + */ + u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1); + if ((masked_linux_sp != (u32_t)sw_ksp[tid]) && + unaligned_only(cause)) { + ldsr_emulate_and_run(tid); + return; + } +#else + ldsr_emulate_and_run(tid); + return; +#endif + + } +#endif + + interrupt_vector = (u32_t)(&trap_handler); + frame_type = UBICOM32_FRAME_TYPE_TRAP; + } else { + /* + * Read the target thread's SP + */ + asm volatile ( + " setcsr %1 \n\t" + " setcsr_flush 0 \n\t" + " setcsr_flush 0 \n\t" + " move.4 %0, SP \n\t" + " setcsr #0 \n\t" + " setcsr_flush 0 \n\t" + : "=m" (linux_sp) + : "m" (read_csr) + ); + } + + /* + * We are delivering an interrupt, count it. + */ + ldsr_interrupt.total++; + + /* + * At this point, we will definitely force this thread to + * a new context, show its interrupts as disabled. + */ + ldsr_thread_irq_disable(tid); + + /* + * Test our current state (user, kernel, interrupt). Save the + * appropriate data and setup for the return. + */ + save_area = ldsr_choose_savearea_and_returnvec(tid, linux_sp, &return_vector); + + /* + * The pt_regs (save_area) contains the type of thread that we are dealing + * with (KERNEL/NORMAL) and is copied into each pt_regs area. We get this + * from the current tasks kernel pt_regs area that always exists at the + * top of the kernel stack. + */ + regs = (struct pt_regs *)((u32_t)sw_ksp[tid] + THREAD_SIZE - sizeof(struct pt_regs) - 8); + save_area->thread_type = regs->thread_type; + + /* + * Preserve the context of the Linux thread. + */ + ldsr_preemptive_context_save(tid, save_area); + + /* + * Load the fram_type into the save_area. + */ + save_area->frame_type = frame_type; + +#ifdef CONFIG_STOP_ON_TRAP + /* + * Before we get backtrace and showing stacks working well, it sometimes + * helps to enter the debugger when a trap occurs before we change the + * thread to handle the fault. This optional code causes all threads to + * stop on every trap frame. One assumes that GDB connected via the + * mailbox interface will be used to recover from this state. + */ + if (frame_type == UBICOM32_FRAME_TYPE_TRAP) { + THREAD_STALL; + } +#endif + +#ifdef DEBUG_LDSR + copy_regs = *save_area; + copy_save_area = save_area; + + old_a0 = save_area->an[0]; + old_a3 = save_area->an[3]; + old_sp = save_area->an[7]; + old_a5 = save_area->an[5]; + old_pc = save_area->pc; +#endif + + /* + * Now we have to switch the kernel thread to run do_IRQ function. + * Set pc to do_IRQ + * Set d0 to vector + * Set d1 to save_area. + * Set a5 to the proper return vector. + */ + asm volatile ( + " setcsr %0 \n\t" + " setcsr_flush 0 \n\t" + " move.4 d0, %5 \n\t" /* d0 = 0 vector # */ + " move.4 d1, %1 \n\t" /* d1 = save_area */ + " move.4 sp, %1 \n\t" /* sp = save_area */ + " move.4 a5, %2 \n\t" /* a5 = return_vector */ + " move.4 pc, %3 \n\t" /* pc = do_IRQ routine. */ + " move.4 trap_cause, #0 \n\t" /* Clear the trap cause + * register */ + " setcsr #0 \n\t" + " setcsr_flush 0 \n\t" + " enable_kernel_ranges %4 \n\t" + " move.4 mt_dbg_active_set, %4 \n\t" /* Activate thread even if + * in dbg/fault state */ + " move.4 mt_active_set, %4 \n\t" /* Restart target + * thread. */ + : + : "r" (write_csr), "r" (save_area), + "r" (return_vector), "r" (interrupt_vector), + "d" (thread_mask), "r" (vector) + : "cc" + ); + thread_enable_mask(thread_mask); +} + +/* + * ldsr_deliver_interrupt() + * Deliver the interrupt to one of the threads or all of the threads. + */ +static void ldsr_deliver_interrupt(int vector, + unsigned long deliver_to, + int all) +{ + unsigned long disabled_threads; + unsigned long possible_threads; + unsigned long trapped_threads; + unsigned long global_locks; + + /* + * Disable all of the threads that we might want to send + * this interrupt to. + */ +retry: + DEBUG_ASSERT(deliver_to); + thread_disable_mask(deliver_to); + + /* + * If any threads are in the trap state, we have to service the + * trap for those threads first. + */ + asm volatile ( + "move.4 %0, MT_TRAP \n\t" + : "=r" (trapped_threads) + : + ); + + trapped_threads &= deliver_to; + if (unlikely(trapped_threads)) { + /* + * all traps will be handled, so clear the trap bit before restarting any threads + */ + ubicom32_clear_interrupt(ldsr_trap_irq); + + /* + * Let the remaining untrapped threads, continue. + */ + deliver_to &= ~trapped_threads; + if (deliver_to) { + thread_enable_mask(deliver_to); + } + + /* + * For the trapped threads force them to handle + * a trap. + */ + while (trapped_threads) { + unsigned long which = ffz(~trapped_threads); + trapped_threads &= ~(1 << which); + ldsr_ctxsw_thread(vector, which); + } + return; + } + + /* + * Can we deliver an interrupt to any of the threads? + */ + disabled_threads = ldsr_thread_get_interrupts(); + possible_threads = deliver_to & ~disabled_threads; + if (unlikely(!possible_threads)) { +#if defined(CONFIG_SMP) + /* + * In the SMP case, we can not wait because 1 cpu might be + * sending an IPI to another cpu which is currently blocked. + * The only way to ensure IPI delivery is to backout and + * keep trying. For SMP, we don't sleep until the interrupts + * are delivered. + */ + thread_enable_mask(deliver_to); + ldsr_backout_of_irq(vector, deliver_to); + return; +#else + /* + * In the UP case, we have nothing to do so we should wait. + * + * Since the INT_MASK0 and INT_MASK1 are "re-loaded" before we + * suspend in the outer loop, we do not need to save them here. + * + * We test that we were awakened for our specific interrupts + * because the ldsr mask/unmask operations will force the ldsr + * awake even if the interrupt on the mainline thread is not + * completed. + */ + unsigned int scratch = 0; + thread_enable_mask(deliver_to); + asm volatile ( + " move.4 INT_MASK0, %1 \n\t" + " move.4 INT_MASK1, #0 \n\t" + + "1: suspend \n\t" + " move.4 %0, INT_STAT0 \n\t" + " and.4 %0, %0, %1 \n\t" + " jmpeq.f 1b \n\t" + + " move.4 INT_CLR0, %2 \n\t" + : "+r" (scratch) + : "d" (ldsr_suspend_mask), "r" (ldsr_soft_irq_mask) + : "cc" + ); + + /* + * This delay is sized to coincide with the time it takes a + * thread to complete the exit (see return_from_interrupt). + */ + ldsr_interrupt.retry++; + __delay(10); + goto retry; +#endif + } + + /* + * If any of the global locks are held, we can not deliver any + * interrupts, we spin delay(10) and then try again. If our + * spinning becomes a bottle neck, we will need to suspend but for + * now lets just spin. + */ + asm volatile ( + "move.4 %0, scratchpad1 \n\t" + : "=r" (global_locks) + : + ); + if (unlikely(global_locks & 0xffff0000)) { + thread_enable_mask(deliver_to); + + /* + * This delay is sized to coincide with the average time it + * takes a thread to release a global lock. + */ + ldsr_interrupt.retry++; + __delay(10); + goto retry; + } + + /* + * Deliver to one cpu. + */ + if (!all) { + /* + * Find our victim and then enable everyone else. + */ + unsigned long victim = ldsr_rotate_threads(possible_threads); + DEBUG_ASSERT((deliver_to & (1 << victim))); + DEBUG_ASSERT((possible_threads & (1 << victim))); + + deliver_to &= ~(1 << victim); + if (deliver_to) { + thread_enable_mask(deliver_to); + } + ldsr_ctxsw_thread(vector, victim); + return; + } + + /* + * If we can't deliver to some threads, wake them + * back up and reset things to deliver to them. + */ + deliver_to &= ~possible_threads; + if (unlikely(deliver_to)) { + thread_enable_mask(deliver_to); + ldsr_backout_of_irq(vector, deliver_to); + } + + /* + * Deliver to all possible threads(s). + */ + while (possible_threads) { + unsigned long victim = ffz(~possible_threads); + possible_threads &= ~(1 << victim); + ldsr_ctxsw_thread(vector, victim); + } +} + +/* + * ldsr_thread() + * This thread acts as the interrupt controller for Linux. + */ +static void ldsr_thread(void *arg) +{ + int stat0; + int stat1; + int interrupt0; + int interrupt1; + long long interrupts; + unsigned long cpus; + +#if !defined(CONFIG_SMP) + /* + * In a non-smp configuration, we can not use the cpu(s) arrays because + * there is not a 1-1 correspondence between cpus(s) and our threads. + * Thus we must get a local idea of the mainline threads and use the + * one and only 1 set as the victim. We do this once before the ldsr + * loop. + * + * In the SMP case, we will use the cpu(s) map to determine which cpu(s) + * are valid to send interrupts to. + */ + int victim = 0; + unsigned int mainline = thread_get_mainline(); + if (mainline == 0) { + panic("no mainline Linux threads to interrupt"); + return; + } + victim = ffz(~mainline); + cpus = (1 << victim); +#endif + + while (1) { + /* + * If one changes this code not to reload the INT_MASK(s), you + * need to know that code in the lock waiting above does not + * reset the MASK registers back; so that code will need to be + * changed. + */ + ldsr_lock_acquire(); + asm volatile ( + " move.4 INT_MASK0, %0 \n\t" + " move.4 INT_MASK1, %1 \n\t" + : + : "U4" (ldsr_interrupt.mask0), "U4" (ldsr_interrupt.mask1) + ); + ldsr_lock_release(); + thread_suspend(); + + /* + * Read the interrupt status registers + */ + asm volatile ( + "move.4 %0, INT_STAT0 \n\t" + "move.4 %1, INT_STAT1 \n\t" + : "=r" (stat0), "=r" (stat1) + : + ); + + /* + * We only care about interrupts that we have been told to care + * about. The interrupt must be enabled, unmasked, and have + * occurred in the hardware. + */ + ldsr_lock_acquire(); + interrupt0 = ldsr_interrupt.enabled0 & + ldsr_interrupt.mask0 & stat0; + interrupt1 = ldsr_interrupt.enabled1 & + ldsr_interrupt.mask1 & stat1; + ldsr_lock_release(); + + /* + * For each interrupt in the "snapshot" we will mask the + * interrupt handle the interrupt (typically calling do_IRQ()). + * + * The interrupt is unmasked by desc->chip->end() function in + * the per chip generic interrupt handling code + * (arch/ubicom32/kernel/irq.c).8 + */ + interrupts = ((unsigned long long)interrupt1 << 32) | + interrupt0; + while (interrupts) { + int all = 0; + int vector = ldsr_rotate_interrupts(interrupts); + interrupts &= ~((unsigned long long)1 << vector); + + /* + * Now mask off this vector so that the LDSR ignores + * it until it is acknowledged. + */ + ldsr_mask_vector(vector); +#if !defined(CONFIG_SMP) + ldsr_deliver_interrupt(vector, cpus, all); +#else + cpus = smp_get_affinity(vector, &all); + if (!cpus) { + /* + * No CPU to deliver to so just leave + * the interrupt unmasked and increase + * the backout count. We will eventually + * return and deliver it again. + */ + ldsr_unmask_vector(vector); + ldsr_interrupt.backout++; + continue; + } + ldsr_deliver_interrupt(vector, cpus, all); +#endif + } + } + + /* NOTREACHED */ +} + +/* + * ldsr_mask_vector() + * Temporarily mask the interrupt vector, turn off the bit in the mask + * register. + */ +void ldsr_mask_vector(unsigned int vector) +{ + unsigned int mask; + if (vector < 32) { + mask = ~(1 << vector); + ldsr_lock_acquire(); + ldsr_interrupt.mask0 &= mask; + ldsr_lock_release(); + thread_resume(ldsr_tid); + return; + } + + mask = ~(1 << (vector - 32)); + ldsr_lock_acquire(); + ldsr_interrupt.mask1 &= mask; + ldsr_lock_release(); + thread_resume(ldsr_tid); +} + +/* + * ldsr_unmask_vector() + * Unmask the interrupt vector so that it can be used, turn on the bit in + * the mask register. + * + * Because it is legal for the interrupt path to disable an interrupt, + * the unmasking code must ensure that disabled interrupts are not + * unmasked. + */ +void ldsr_unmask_vector(unsigned int vector) +{ + unsigned int mask; + if (vector < 32) { + mask = (1 << vector); + ldsr_lock_acquire(); + ldsr_interrupt.mask0 |= (mask & ldsr_interrupt.enabled0); + ldsr_lock_release(); + thread_resume(ldsr_tid); + return; + } + + mask = (1 << (vector - 32)); + ldsr_lock_acquire(); + ldsr_interrupt.mask1 |= (mask & ldsr_interrupt.enabled1); + ldsr_lock_release(); + thread_resume(ldsr_tid); +} + +/* + * ldsr_enable_vector() + * The LDSR implements an interrupt controller and has a local (to the + * LDSR) copy of its interrupt mask. + */ +void ldsr_enable_vector(unsigned int vector) +{ + unsigned int mask; + if (vector < 32) { + mask = (1 << vector); + ldsr_lock_acquire(); + ldsr_interrupt.enabled0 |= mask; + ldsr_interrupt.mask0 |= mask; + ldsr_lock_release(); + thread_resume(ldsr_tid); + return; + } + + mask = (1 << (vector - 32)); + ldsr_lock_acquire(); + ldsr_interrupt.enabled1 |= mask; + ldsr_interrupt.mask1 |= mask; + ldsr_lock_release(); + thread_resume(ldsr_tid); +} + +/* + * ldsr_disable_vector() + * The LDSR implements an interrupt controller and has a local (to the + * LDSR) copy of its interrupt mask. + */ +void ldsr_disable_vector(unsigned int vector) +{ + unsigned int mask; + + if (vector < 32) { + mask = ~(1 << vector); + ldsr_lock_acquire(); + ldsr_interrupt.enabled0 &= mask; + ldsr_interrupt.mask0 &= mask; + ldsr_lock_release(); + thread_resume(ldsr_tid); + return; + } + + mask = ~(1 << (vector - 32)); + ldsr_lock_acquire(); + ldsr_interrupt.enabled1 &= mask; + ldsr_interrupt.mask1 &= mask; + ldsr_lock_release(); + thread_resume(ldsr_tid); +} + +/* + * ldsr_get_threadid() + * Return the threadid of the LDSR thread. + */ +thread_t ldsr_get_threadid(void) +{ + return ldsr_tid; +} + +/* + * ldsr_set_trap_irq() + * Save away the trap Soft IRQ + * + * See the per thread lock suspend code above for an explination. + */ +void ldsr_set_trap_irq(unsigned int irq) +{ + ldsr_trap_irq = irq; + ldsr_trap_irq_mask = (1 << irq); + ldsr_suspend_mask |= ldsr_trap_irq_mask; +} + +/* + * ldsr_init() + * Initialize the LDSR (Interrupt Controller) + */ +void ldsr_init(void) +{ +#if defined(CONFIG_IRQSTACKS) + int i; + union irq_ctx *icp; +#endif + + void *stack_high = (void *)ldsr_stack_space; + stack_high += sizeof(ldsr_stack_space); + stack_high -= 8; + + + /* + * Obtain a soft IRQ to use + */ + if (irq_soft_alloc(&ldsr_soft_irq) < 0) { + panic("no software IRQ is available\n"); + return; + } + ldsr_soft_irq_mask |= (1 << ldsr_soft_irq); + ldsr_suspend_mask |= ldsr_soft_irq_mask; + + /* + * Now allocate and start the LDSR thread. + */ + ldsr_tid = thread_alloc(); + if (ldsr_tid < 0) { + panic("no thread available to run LDSR"); + return; + } + +#if defined(CONFIG_IRQSTACKS) + /* + * Initialize the per-cpu irq thread_info structure that + * is at the top of each per-cpu irq stack. + */ + icp = (union irq_ctx *) + (((unsigned long)percpu_irq_stacks + (THREAD_SIZE - 1)) & ~(THREAD_SIZE - 1)); + for (i = 0; i < NR_CPUS; i++) { + struct thread_info *ti = &(icp->tinfo); + ti->task = NULL; + ti->exec_domain = NULL; + ti->cpu = i; + ti->preempt_count = 0; + ti->interrupt_nesting = 0; + percpu_irq_ctxs[i] = icp++; + } +#endif + thread_start(ldsr_tid, ldsr_thread, NULL, + stack_high, THREAD_TYPE_NORMAL); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/module.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/module.c new file mode 100644 index 000000000..3d29dc2b8 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/module.c @@ -0,0 +1,463 @@ +/* + * arch/ubicom32/kernel/module.c + * Ubicom32 architecture loadable module support. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt...) +#endif + +static void _module_free_ocm(struct module *mod) +{ + printk(KERN_INFO "module arch cleanup %s: OCM instruction memory free " + " of %d @%p\n", mod->name, mod->arch.ocm_inst_size, + mod->arch.ocm_inst); + + if (mod->arch.ocm_inst) { + ocm_inst_free(mod->arch.ocm_inst); + mod->arch.ocm_inst = 0; + mod->arch.ocm_inst_size = 0; + } +} + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ + + /* + * This is expected to be final module free, use this to prune the + * ocm + */ + if (module_region && module_region == mod->module_core) + _module_free_ocm(mod); + +} + +/* + * module_frob_arch_sections() + * Called from kernel/module.c allowing arch specific handling of + * sections/headers. + */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + Elf_Shdr *s, *sechdrs_end; + void *ocm_inst = NULL; + int ocm_inst_size = 0; + + /* + * Ubicom32 v3 and v4 are almost binary compatible but not completely. + * To be safe check that the module was compiled with the correct -march + * which is flags. + */ +#ifdef CONFIG_UBICOM32_V4 + if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V4) { + printk(KERN_WARNING "Module %s was not compiled for " + "ubicom32v4, elf_flags:%x,\n", + mod->name, hdr->e_flags); + return -ENOEXEC; + } +#elif defined CONFIG_UBICOM32_V3 + if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V3) { + printk(KERN_WARNING "Module %s was not compiled for " + "ubicom32v3, elf_flags:%x\n", + mod->name, hdr->e_flags); + return -ENOEXEC; + } +#else +#error Unknown/Unsupported ubicom32 architecture. +#endif + + /* + * XXX: sechdrs are vmalloced in kernel/module.c + * and would be vfreed just after module is loaded, + * so we hack to keep the only information we needed + * in mod->arch to correctly free L1 I/D sram later. + * NOTE: this breaks the semantic of mod->arch structure. + */ + sechdrs_end = sechdrs + hdr->e_shnum; + for (s = sechdrs; s < sechdrs_end; ++s) { + if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0) + ocm_inst_size += s->sh_size; + } + + if (!ocm_inst_size) + return 0; + + ocm_inst = ocm_inst_alloc(ocm_inst_size, 0 /* internal */); + if (ocm_inst == NULL) { +#ifdef CONFIG_OCM_MODULES_FALLBACK_TO_DDR + printk(KERN_WARNING + "module %s: OCM instruction memory allocation of %d" + "failed, fallback to DDR\n", mod->name, ocm_inst_size); + return 0; +#else + printk(KERN_ERR + "module %s: OCM instruction memory allocation of %d" + "failed.\n", mod->name, ocm_inst_size); + return -ENOMEM; +#endif + } + + mod->arch.ocm_inst = ocm_inst; + mod->arch.ocm_inst_size = ocm_inst_size; + + printk(KERN_INFO + "module %s: OCM instruction memory allocation of %d @%p\n", + mod->name, mod->arch.ocm_inst_size, mod->arch.ocm_inst); + + for (s = sechdrs; s < sechdrs_end; ++s) { + if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0) { + memcpy(ocm_inst, (void *)s->sh_addr, s->sh_size); + s->sh_flags &= ~SHF_ALLOC; + s->sh_addr = (unsigned long)ocm_inst; + ocm_inst += s->sh_size; + } + } + + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + DEBUGP("Invalid Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + return -EINVAL; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location; + uint32_t insn; + + DEBUGP("Applying relocate_add section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + uint32_t v; + const int elf32_rtype = ELF32_R_TYPE(rel[i].r_info); + + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset; + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + + v = rel[i].r_addend + sym->st_value; + + + switch (elf32_rtype) { + case R_UBICOM32_32: + { + /* + * Store the 32 bit relocation as is. + */ + *location = v; + break; + } + case R_UBICOM32_HI24: + { + /* + * 24 bit relocation that is part of the MOVEAI + * instruction. The 24 bits come from bits 7 - 30 of the + * relocation. Theses bits eventually get split into 2 + * fields in the instruction encoding. + * + * - Bits 7 - 27 of the relocation are encoded into bits + * 0 - 20 of the instruction. + * + * - Bits 28 - 30 of the relocation are encoded into + * bit 24 - 26 of the instruction. + */ + uint32_t valid24 = (v >> 7) & 0xffffff; + insn = *location; + + insn &= ~(0x1fffff | (0x7 << 24)); + insn |= (valid24 & 0x1fffff); + insn |= ((valid24 & 0xe00000) << 3); + *location = insn; + } + break; + case R_UBICOM32_LO7_S: + case R_UBICOM32_LO7_2_S: + case R_UBICOM32_LO7_4_S: + { + /* + * Bits 0 - 6 of the relocation are encoded into the + * 7bit unsigned immediate fields of the SOURCE-1 field + * of the instruction. The immediate value is left + * shifted by (0, 1, 2) based on the operand size. + */ + uint32_t valid7 = v & 0x7f; + insn = *location; + + if (elf32_rtype == R_UBICOM32_LO7_2_S) { + valid7 >>= 1; + } else if (elf32_rtype == R_UBICOM32_LO7_4_S) { + valid7 >>= 2; + } + + insn &= ~(0x1f | (0x3 << 8)); + insn |= (valid7 & 0x1f); + insn |= ((valid7 & 0x60) << 3); + *location = insn; + } + break; + case R_UBICOM32_LO7_D: + case R_UBICOM32_LO7_2_D: + case R_UBICOM32_LO7_4_D: + { + /* + * Bits 0 - 6 of the relocation are encoded into the + * 7bit unsigned immediate fields of the DESTINATION + * field of the instruction. The immediate value is + * left shifted by (0, 1, 2) based on the operand size. + */ + uint32_t valid7 = v & 0x7f; + insn = *location; + + if (elf32_rtype == R_UBICOM32_LO7_2_D) { + valid7 >>= 1; + } else if (elf32_rtype == R_UBICOM32_LO7_4_D) { + valid7 >>= 2; + } + + insn &= ~((0x1f | (0x3 << 8)) << 16); + insn |= ((valid7 & 0x1f) << 16); + insn |= ((valid7 & 0x60) << 19); + *location = insn; + } + break; + case R_UBICOM32_LO7_CALLI: + case R_UBICOM32_LO16_CALLI: + { + /* + * Extract the offset for a CALLI instruction. The + * offsets can be either 7 bits or 18 bits. Since all + * instructions in ubicom32 architecture are at work + * aligned addresses the truncated offset is right + * shifted by 2 before being encoded in the instruction. + */ + uint32_t val; + if (elf32_rtype == R_UBICOM32_LO7_CALLI) { + val = v & 0x7f; + } else { + val = v & 0x3ffff; + } + + val >>= 2; + + insn = *location; + + insn &= ~0x071f071f; + insn |= (val & 0x1f) << 0; + val >>= 5; + insn |= (val & 0x07) << 8; + val >>= 3; + insn |= (val & 0x1f) << 16; + val >>= 5; + insn |= (val & 0x07) << 24; + *location = insn; + } + break; + case R_UBICOM32_24_PCREL: + { + /* + * Extract 26 bit signed PC relative offset for CALL + * instructions. Since instruction addresses are word + * aligned the offset is right shited by 2 before + * encoding into instruction. + */ + int32_t val = v - (int32_t)location; + + /* + * Check that the top 7 bits are all equal to the sign + * bit (26), i.e all 0's or all 1's. If they are not then + * the absolute difference is greater than 25 bits. + */ + if (((uint32_t)val & 0xFE000000) != 0xFE000000 && + ((uint32_t)val & 0xFE000000) != 0x0) { + /* + * The relocation is beyond our addressable + * range with a 26 bit call. + */ + printk(KERN_ERR "module %s: PC Relative " + "relocation out of range: " + "%u (%x->%x, %x)\n", + me->name, elf32_rtype, + v, (uint32_t) location, val); + return -ENOEXEC; + } + + val = (val & 0x3ffffff) >> 2; + insn = *location; + insn = insn & 0xf8e00000; + + insn |= (val >> 21) << 24; + insn |= (val & 0x1fffff); + *location = insn; + } + break; + case R_UBICOM32_LO16: + case R_UBICOM32_HI16: + { + /* + * 16 bit immediate value that is encoded into bit 0 - + * 15 of the instruction. + */ + uint32_t val; + + if (elf32_rtype == R_UBICOM32_LO16) { + val = v & 0xffff; + } else { + val = (v >> 16) & 0xffff; + } + + insn = *location; + insn &= 0xffff0000; + + insn |= val; + *location = insn; + } + break; + case R_UBICOM32_21_PCREL: + { + /* + * Extract 23 bit signed PC relative offset for JMP + * instructions. Since instruction addresses are word + * aligned the offset is right shited by 2 before + * encoding into instruction. + */ + int32_t val = v - (int32_t)location; + + val = (val & 0x7fffff) >> 2; + insn = *location; + insn = insn & 0xffe00000; + + insn |= (val >> 21) << 24; + insn |= val; + *location = insn; + } + break; + default: + BUG(); + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + me->name, elf32_rtype); + return -ENOEXEC; + } + } + return 0; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *mod) +{ + unsigned int i, strindex = 0, symindex = 0; + char *secstrings; + int err; + + err = module_bug_finalize(hdr, sechdrs, mod); + if (err) + return err; + + if (!mod->arch.ocm_inst) { + /* + * No OCM code, so nothing more to do. + */ + return 0; + } + + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + for (i = 1; i < hdr->e_shnum; i++) { + /* Internal symbols and strings. */ + if (sechdrs[i].sh_type == SHT_SYMTAB) { + symindex = i; + strindex = sechdrs[i].sh_link; + } + } + + for (i = 1; i < hdr->e_shnum; i++) { + const char *strtab = (char *)sechdrs[strindex].sh_addr; + unsigned int info = sechdrs[i].sh_info; + + /* Not a valid relocation section? */ + if (info >= hdr->e_shnum) + continue; + + if ((sechdrs[i].sh_type == SHT_RELA) && + (strncmp(".rela.ocm_text", + secstrings + sechdrs[i].sh_name, 5 + 9) == 0)) { + err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab, + symindex, i, mod); + if (err) + return err; + } + } + + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ + module_bug_cleanup(mod); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/os_node.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/os_node.c new file mode 100644 index 000000000..9e014d5cb --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/os_node.c @@ -0,0 +1,88 @@ +/* + * arch/ubicom32/kernel/os_node.c + * + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + */ +#include "linux/types.h" +#include "linux/linkage.h" +#include "linux/uts.h" +#include "linux/utsrelease.h" +#include "linux/version.h" +#include +#include +#include + +extern asmlinkage void *_start; + +/* + * This file provides static information to the boot code allowing it to decide + * if the os is compatible. Thus hopefully enabling the boot code to prevent + * accidentally booting a kernel that has no hope of running. + */ +struct os_node { + struct devtree_node node; + unsigned long version; /* Always 1 */ + unsigned long entry_point; + const char os_name[32]; /* For diagnostic purposes only */ + const char os_version_str[32]; + unsigned long os_version_num; + unsigned long expected_ocm_code_start;/* OS Code */ + unsigned long expected_ocm_data_end; /* OS Data */ + unsigned long expected_ram_start; + unsigned long expected_ram_end; + unsigned long arch_version; + unsigned long expected_os_syscall_begin; + unsigned long expected_os_syscall_end; +}; + + +extern void __os_syscall_begin; +extern void __os_syscall_end; +/* + * The os_node is only referenced by head.S and should never be modified at + * run-time. + */ +asmlinkage const struct os_node _os_node = { + .node = { + .next = NULL, + .name = { "OS" }, + .magic = 0x10203040, + }, + .version = 0x10002, + .entry_point = (unsigned long)&_start, +#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE + .expected_ocm_code_start = OCMSTART + APP_OCM_CODE_SIZE, + .expected_ocm_data_end = OCMEND - APP_OCM_DATA_SIZE, +#else + .expected_ocm_code_start = OCMEND, + .expected_ocm_data_end = OCMEND, +#endif + .os_name = { UTS_SYSNAME }, + .os_version_str = { UTS_RELEASE }, + .os_version_num = LINUX_VERSION_CODE, + .expected_ram_start = KERNELSTART, + .expected_ram_end = SDRAMSTART + CONFIG_MIN_RAMSIZE, + .arch_version = UBICOM32_ARCH_VERSION, + .expected_os_syscall_begin = (unsigned long)&__os_syscall_begin, + .expected_os_syscall_end = (unsigned long)&__os_syscall_end, + + +}; diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/process.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/process.c new file mode 100644 index 000000000..23872fed0 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/process.c @@ -0,0 +1,634 @@ +/* + * arch/ubicom32/kernel/process.c + * Ubicom32 architecture-dependent process handling. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1995 Hamish Macdonald + * + * 68060 fixes by Jesper Skov + * + * uClinux changes + * Copyright (C) 2000-2002, David McCullough + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DUMP_RANGE_REGISTER(REG, IDX) asm volatile ( \ + " move.4 %0, "REG"_RANGE"IDX"_EN \n\t" \ + " move.4 %1, "REG"_RANGE"IDX"_LO \n\t" \ + " move.4 %2, "REG"_RANGE"IDX"_HI \n\t" \ + : "=d"(en), "=d"(lo), "=d"(hi) \ + ); \ + printk(KERN_NOTICE REG"Range"IDX": en:%08x, range: %08x-%08x\n", \ + (unsigned int)en, \ + (unsigned int)lo, \ + (unsigned int)hi) + +asmlinkage void ret_from_fork(void); + +void (*pm_power_off)(void) = machine_power_off; +EXPORT_SYMBOL(pm_power_off); + +/* machine-dependent / hardware-specific power functions */ +void (*mach_reset)(void); +void (*mach_halt)(void); +void (*mach_power_off)(void); + +/* + * cpu_idle() + * The idle thread. + * + * Our idle loop suspends and is woken up by a timer interrupt. + */ +void cpu_idle(void) +{ + while (1) { + local_irq_disable(); + while (!need_resched()) { + local_irq_enable(); + thread_suspend(); + local_irq_disable(); + } + local_irq_enable(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } +} + +/* + * dump_fpu() + * + * Fill in the fpu structure for a core dump. (just a stub as we don't have + * an fpu) + */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs) +{ + return 1; +} + +/* + * machine_restart() + * Resets the system. + */ +void machine_restart(char *__unused) +{ + /* + * Disable all threads except myself. We can do this + * directly without needing to call smp_send_stop + * because we have a unique architecture where + * one thread can disable one or more other threads. + */ + thread_disable_others(); + + /* + * Call the hardware-specific machine reset function. + */ + if (mach_reset) { + mach_reset(); + } + + printk(KERN_EMERG "System Restarting\n"); + + /* + * Set watchdog to trigger (after 1ms delay) (12 Mhz is the fixed OSC) + */ + UBICOM32_IO_TIMER->tkey = TIMER_TKEYVAL; + UBICOM32_IO_TIMER->wdcom = UBICOM32_IO_TIMER->mptval + + (12000000 / 1000); + UBICOM32_IO_TIMER->wdcfg = 0; + UBICOM32_IO_TIMER->tkey = 0; + + /* + * Wait for watchdog + */ + asm volatile ( + " move.4 MT_EN, #0 \n\t" + " pipe_flush 0 \n\t" + ); + + local_irq_disable(); + for (;;) { + thread_suspend(); + } +} + +/* + * machine_halt() + * Halt the machine. + * + * Similar to machine_power_off, but don't shut off power. Add code + * here to freeze the system for e.g. post-mortem debug purpose when + * possible. This halt has nothing to do with the idle halt. + */ +void machine_halt(void) +{ + /* + * Disable all threads except myself. We can do this + * directly without needing to call smp_send_stop + * because we have a unique architecture where + * one thread can disable one or more other threads. + */ + thread_disable_others(); + + /* + * Call the hardware-specific machine halt function. + */ + if (mach_halt) { + mach_halt(); + } + + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + local_irq_disable(); + for (;;) { + thread_suspend(); + } +} + +/* + * machine_power_off() + * Turn the power off, if a power off handler is defined, otherwise, spin + * endlessly. + */ +void machine_power_off(void) +{ + /* + * Disable all threads except myself. We can do this + * directly without needing to call smp_send_stop + * because we have a unique architecture where + * one thread can disable one or more other threads. + */ + thread_disable_others(); + + /* + * Call the hardware-specific machine power off function. + */ + if (mach_power_off) { + mach_power_off(); + } + + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + local_irq_disable(); + for (;;) { + thread_suspend(); + } +} + +/* + * address_is_valid() + * check if an address is valid -- (for read access) + */ +static bool address_is_valid(const void *address) +{ + int addr = (int)address; + unsigned long socm, eocm, sdram, edram; + + if (addr & 3) + return false; + + processor_ocm(&socm, &eocm); + processor_dram(&sdram, &edram); + if (addr >= socm && addr < eocm) + return true; + + if (addr >= sdram && addr < edram) + return true; + + return false; +} + +/* + * vma_path_name_is_valid() + * check if path_name of a vma is a valid string + */ +static bool vma_path_name_is_valid(const char *str) +{ +#define MAX_NAME_LEN 256 + int i = 0; + if (!address_is_valid(str)) + return false; + + for (; i < MAX_NAME_LEN; i++, str++) { + if (*str == '\0') + return true; + } + + return false; +} + +/* + * show_vmas() + * show vma info of a process + */ +void show_vmas(struct task_struct *task) +{ +#ifdef CONFIG_DEBUG_VERBOSE +#define UBICOM32_MAX_VMA_COUNT 1024 + + struct vm_area_struct *vma; + struct file *file; + char *name = ""; + int flags, loop = 0; + + printk(KERN_NOTICE "Start of vma list\n"); + + if (!address_is_valid(task) || !address_is_valid(task->mm)) + goto error; + + vma = task->mm->mmap; + while (vma) { + if (!address_is_valid(vma)) + goto error; + + flags = vma->vm_flags; + file = vma->vm_file; + + if (file) { + /* seems better to use dentry op here, but sanity check is easier this way */ + if (!address_is_valid(file) || !address_is_valid(file->f_path.dentry) || !vma_path_name_is_valid(file->f_path.dentry->d_name.name)) + goto error; + + name = (char *)file->f_path.dentry->d_name.name; + } + + /* Similar to /proc/pid/maps format */ + printk(KERN_NOTICE "%08lx-%08lx %c%c%c%c %08lx %s\n", + vma->vm_start, + vma->vm_end, + flags & VM_READ ? 'r' : '-', + flags & VM_WRITE ? 'w' : '-', + flags & VM_EXEC ? 'x' : '-', + flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', + vma->vm_pgoff << PAGE_SHIFT, + name); + + vma = vma->vm_next; + + if (loop++ > UBICOM32_MAX_VMA_COUNT) + goto error; + } + + printk(KERN_NOTICE "End of vma list\n"); + return; + +error: + printk(KERN_NOTICE "\nCorrupted vma list, abort!\n"); +#endif +} + +/* + * show_regs() + * Print out all of the registers. + */ +void show_regs(struct pt_regs *regs) +{ + unsigned int i; + unsigned int en, lo, hi; + + printk(KERN_NOTICE "regs: %p, tid: %d\n", + (void *)regs, + thread_get_self()); + + printk(KERN_NOTICE "pc: %08x, previous_pc: %08x\n\n", + (unsigned int)regs->pc, + (unsigned int)regs->previous_pc); + + printk(KERN_NOTICE "Data registers\n"); + for (i = 0; i < 16; i++) { + printk("D%02d: %08x, ", i, (unsigned int)regs->dn[i]); + if ((i % 4) == 3) { + printk("\n"); + } + } + printk("\n"); + + printk(KERN_NOTICE "Address registers\n"); + for (i = 0; i < 8; i++) { + printk("A%02d: %08x, ", i, (unsigned int)regs->an[i]); + if ((i % 4) == 3) { + printk("\n"); + } + } + printk("\n"); + + printk(KERN_NOTICE "acc0: %08x-%08x, acc1: %08x-%08x\n", + (unsigned int)regs->acc0[1], + (unsigned int)regs->acc0[0], + (unsigned int)regs->acc1[1], + (unsigned int)regs->acc1[0]); + + printk(KERN_NOTICE "mac_rc16: %08x, source3: %08x\n", + (unsigned int)regs->mac_rc16, + (unsigned int)regs->source3); + + printk(KERN_NOTICE "inst_cnt: %08x, csr: %08x\n", + (unsigned int)regs->inst_cnt, + (unsigned int)regs->csr); + + printk(KERN_NOTICE "int_mask0: %08x, int_mask1: %08x\n", + (unsigned int)regs->int_mask0, + (unsigned int)regs->int_mask1); + + /* + * Dump range registers + */ + DUMP_RANGE_REGISTER("I", "0"); + DUMP_RANGE_REGISTER("I", "1"); + DUMP_RANGE_REGISTER("I", "2"); + DUMP_RANGE_REGISTER("I", "3"); + DUMP_RANGE_REGISTER("D", "0"); + DUMP_RANGE_REGISTER("D", "1"); + DUMP_RANGE_REGISTER("D", "2"); + DUMP_RANGE_REGISTER("D", "3"); + DUMP_RANGE_REGISTER("D", "4"); + + printk(KERN_NOTICE "frame_type: %d, nesting_level: %d, thread_type %d\n\n", + (int)regs->frame_type, + (int)regs->nesting_level, + (int)regs->thread_type); +} + +/* + * kernel_thread_helper() + * On execution d0 will be 0, d1 will be the argument to be passed to the + * kernel function. d2 contains the kernel function that needs to get + * called. d3 will contain address to do_exit which need to get moved + * into a5. On return from fork the child thread d0 will be 0. We call + * this dummy function which in turn loads the argument + */ +asmlinkage void kernel_thread_helper(void); + +/* + * kernel_thread() + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof(regs)); + + regs.dn[1] = (unsigned long)arg; + regs.dn[2] = (unsigned long)fn; + regs.dn[3] = (unsigned long)do_exit; + regs.an[5] = (unsigned long)kernel_thread_helper; + regs.pc = (unsigned long)kernel_thread_helper; + regs.nesting_level = 0; + regs.thread_type = KERNEL_THREAD; + + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, + 0, ®s, 0, NULL, NULL); +} +EXPORT_SYMBOL(kernel_thread); + +/* + * flush_thread() + * XXX todo + */ +void flush_thread(void) +{ + /* XXX todo */ +} + +/* + * sys_fork() + * Not implemented on no-mmu. + */ +asmlinkage int sys_fork(struct pt_regs *regs) +{ + /* fork almost works, enough to trick you into looking elsewhere :-( */ + return -EINVAL; +} + +/* + * sys_vfork() + * By the time we get here, the non-volatile registers have also been saved + * on the stack. We do some ugly pointer stuff here.. (see also copy_thread + * which does context copy). + */ +asmlinkage int sys_vfork(struct pt_regs *regs) +{ + unsigned long old_sp = regs->an[7]; + unsigned long old_a5 = regs->an[5]; + unsigned long old_return_address; + long do_fork_return; + + /* + * Read the old retrun address from the stack. + */ + if (copy_from_user(&old_return_address, + (void *)old_sp, sizeof(unsigned long))) { + force_sig(SIGSEGV, current); + return 0; + } + + /* + * Pop the vfork call frame by setting a5 and pc to the old_return + * address and incrementing the stack pointer by 4. + */ + regs->an[5] = old_return_address; + regs->pc = old_return_address; + regs->an[7] += 4; + + do_fork_return = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, + regs->an[7], regs, 0, NULL, NULL); + + /* + * Now we have to test if the return code is an error. If it is an error + * then restore the frame and we will execute error processing in user + * space. Other wise the child and the parent will return to the correct + * places. + */ + if ((unsigned long)(do_fork_return) >= (unsigned long)(-125)) { + /* + * Error case. We need to restore the frame. + */ + regs->an[5] = old_a5; + regs->pc = old_a5; + regs->an[7] = old_sp; + } + + return do_fork_return; +} + +/* + * sys_clone() + * creates a child thread. + */ +asmlinkage int sys_clone(unsigned long clone_flags, + unsigned long newsp, + struct pt_regs *regs) +{ + if (!newsp) + newsp = regs->an[7]; + return do_fork(clone_flags, newsp, regs, 0, + NULL, NULL); +} + +/* + * copy_thread() + * low level thread copy, only used by do_fork in kernel/fork.c + */ +int copy_thread(unsigned long clone_flags, + unsigned long usp, unsigned long topstk, + struct task_struct *p, struct pt_regs *regs) + +{ + struct pt_regs *childregs; + + childregs = (struct pt_regs *) + (task_stack_page(p) + THREAD_SIZE - 8) - 1; + + *childregs = *regs; + + /* + * Set return value for child to be 0. + */ + childregs->dn[0] = 0; + + if (usp) + childregs->an[7] = usp; + else + childregs->an[7] = (unsigned long)task_stack_page(p) + + THREAD_SIZE - 8; + + /* + * Set up the switch_to frame to return to "ret_from_fork" + */ + p->thread.a5 = (unsigned long)ret_from_fork; + p->thread.sp = (unsigned long)childregs; + + return 0; +} + +/* + * sys_execve() + * executes a new program. + */ +asmlinkage int sys_execve(char *name, char **argv, + char **envp, struct pt_regs *regs) +{ + int error; + char *filename; + + lock_kernel(); + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); + asm (" .global sys_execve_complete\n" + " sys_execve_complete:"); +out: + unlock_kernel(); + return error; +} + +/* + * Return saved PC of a blocked thread. + */ +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + return tsk->thread.a5; +} + + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long pc; + + /* + * If we don't have a process, or it is not the current + * one or not RUNNING, it makes no sense to ask for a + * wchan. + */ + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + /* + * TODO: If the process is in the middle of schedule, we + * are supposed to do something different but for now we + * will return the same thing in both situations. + */ + pc = thread_saved_pc(p); + if (in_sched_functions(pc)) + return pc; + return pc; +} + + +/* + * Infrequently used interface to dump task registers to core files. + */ +int dump_task_regs(struct task_struct *task, elf_gregset_t *elfregs) +{ + struct pt_regs *regs = task_pt_regs(task); + *(struct pt_regs *)elfregs = *regs; + + return 1; +} + +/* + * __switch_to is the function that implements the contex save and + * switch within the kernel. Since this is a function call very few + * registers have to be saved to pull this off. d0 holds prev and we + * want to preserve it. prev_switch is a pointer to task->thread + * structure. This is where we will save the register state. next_switch + * is pointer to the next task's thread structure that holds the + * registers. + */ +asmlinkage void *__switch_to(struct task_struct *prev, + struct thread_struct *prev_switch, + struct thread_struct *next_switch) + __attribute__((naked)); diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c new file mode 100644 index 000000000..55d1bdf62 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c @@ -0,0 +1,348 @@ +/* + * arch/ubicom32/kernel/processor.c + * Ubicom32 architecture processor info implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct procnode { + struct devtree_node dn; + unsigned int threads; + unsigned int timers; + unsigned int frequency; + unsigned int ddr_frequency; + unsigned int interrupt0; + unsigned int interrupt1; + void *socm; + void *eocm; + void *sdram; + void *edram; + unsigned int arch_version; + void *os_syscall_begin; + void *os_syscall_end; +}; + +struct procnode *pn; + +/* + * show_processorinfo() + * Print the actual processor information. + */ +static void show_processorinfo(struct seq_file *m) +{ + char *cpu, *mmu, *fpu; + unsigned int clockfreq; + unsigned int chipid; + + cpu = CPU; + mmu = "none"; + fpu = "none"; + + asm volatile ( + "move.4 %0, CHIP_ID \n\t" + : "=r" (chipid) + ); + + /* + * General Processor Information. + */ + seq_printf(m, "Vendor:\t\t%s\n", "Ubicom"); + seq_printf(m, "CPU:\t\t%s\n", cpu); + seq_printf(m, "MMU:\t\t%s\n", mmu); + seq_printf(m, "FPU:\t\t%s\n", fpu); + seq_printf(m, "Arch:\t\t%hx\n", chipid >> 16); + seq_printf(m, "Rev:\t\t%hx\n", (chipid & 0xffff)); + + /* + * Now compute the clock frequency in Mhz. + */ + clockfreq = processor_frequency(); + seq_printf(m, "Clock Freq:\t%u.0 MHz\n", + clockfreq / 1000000); + seq_printf(m, "DDR Freq:\t%u.0 MHz\n", + pn ? pn->ddr_frequency / 1000000 : 0); + seq_printf(m, "BogoMips:\t%lu.%02lu\n", + (loops_per_jiffy * HZ) / 500000, + ((loops_per_jiffy * HZ) / 5000) % 100); + seq_printf(m, "Calibration:\t%lu loops\n", (loops_per_jiffy * HZ)); +} + +/* + * show_cpuinfo() + * Get CPU information for use by the procfs. + */ +static int show_cpuinfo(struct seq_file *m, void *v) +{ + unsigned long n = (unsigned long)v - 1; + +#if defined(CONFIG_SMP) + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, n); +#endif + + /* + * Print the general processor information on the first + * call. + */ + if (n == 0) { + show_processorinfo(m); + } + +#if defined(CONFIG_SMP) + /* + * For each hwthread, print if this hwthread is running Linux + * or is an I/O thread. + */ + if (cpu_isset(n, cpu_online_map)) { + seq_printf(m, "cpu[%02lu]:\tthread id - %lu\n", n, p->tid); + } else { + seq_printf(m, "cpu[%02lu]:\toff-line\n", n); + } +#endif + return 0; + +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + unsigned long i = *pos; + + return i < NR_CPUS ? (void *)(i + 1) : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +const struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + +/* + * processor_timers() + * Returns the timers available to Linux. + */ +unsigned int processor_timers(void) +{ + if (!pn) { + return 0; + } + return pn->timers; +} + +/* + * processor_threads() + * Returns the threads available to Linux. + */ +unsigned int processor_threads(void) +{ + if (!pn) { + return 0; + } + return pn->threads; +} + +/* + * processor_frequency() + * Returns the frequency of the system clock. + */ +unsigned int processor_frequency(void) +{ + if (!pn) { + return 0; + } + return pn->frequency; +} +EXPORT_SYMBOL(processor_frequency); + +/* + * processor_interrupts() + * Return the interrupts that are setup at boot time. + */ +int processor_interrupts(unsigned int *int0, unsigned int *int1) +{ + if (!pn) { + return -EFAULT; + } + + if (int0) { + *int0 = pn->interrupt0; + } + + if (int1) { + *int1 = pn->interrupt1; + } + return 0; +} + +/* + * processor_ocm() + * Returns the start and end of OCM available to Linux. + */ +void processor_ocm(unsigned long *socm, unsigned long *eocm) +{ + *socm = (unsigned long)pn->socm; + *eocm = (unsigned long)pn->eocm; +} + +/* + * processor_dram() + * Returns the start and end of dram available to Linux. + */ +void processor_dram(unsigned long *sdram, unsigned long *edram) +{ + *sdram = (unsigned long)pn->sdram; + *edram = (unsigned long)pn->edram; +} + +/* + * processor_validate_failed() + * Returns the dram available to Linux. + */ +static noinline void processor_validate_failed(void) +{ + while (1) + THREAD_STALL; +} + +/* + * processor_validate() + * Validates the procnode against limitations of this link/built. + */ +static void processor_validate(void) +{ + void *dram_start = (void *)(KERNELSTART); + void *dram_end = (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE); +#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE + void *ocm_code_start = (void *)(OCMSTART + APP_OCM_CODE_SIZE); + void *ocm_data_end = (void *)(OCMEND - APP_OCM_DATA_SIZE); +#endif + extern void __os_syscall_begin; + extern void __os_syscall_end; + int proc_node_valid = 1; + + if (!pn) { + printk(KERN_ERR "ERROR: processor node not found\n"); + goto error; + } + + + if (dram_start < pn->sdram || dram_end > pn->edram) { + printk(KERN_ERR "ERROR: processor dram mismatch %p-%p " + "available but we are expecting %p-%p\n", + pn->sdram, pn->edram, dram_start, dram_end); + proc_node_valid = 0; + } else { + printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n", + pn->sdram, pn->edram, dram_start, dram_end); + } + if (&__os_syscall_begin < pn->os_syscall_begin || + &__os_syscall_end > pn->os_syscall_end) { + printk(KERN_ERR "ERROR: processor syscall area mismatch " + "%p-%p available but we are expecting %p-%p\n", + pn->os_syscall_begin, pn->os_syscall_end, + &__os_syscall_begin, &__os_syscall_end); + proc_node_valid = 0; + } else { + printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n", + pn->sdram, pn->edram, dram_start, dram_end); + } +#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE + if (ocm_code_start < pn->socm || ocm_data_end > pn->eocm) { + printk(KERN_ERR "ERROR: processor ocm mismatch %p-%p " + "available but we are expecting %p-%p\n", + pn->socm, pn->eocm, ocm_code_start, ocm_data_end); + proc_node_valid = 0; + } else { + printk(KERN_INFO "processor ocm %p-%p, expecting %p-%p\n", + pn->socm, pn->eocm, ocm_code_start, ocm_data_end); + + } +#endif + + if (UBICOM32_ARCH_VERSION != pn->arch_version) { + printk(KERN_ERR "ERROR: processor arch mismatch, kernel" + "compiled for %d found %d\n", + UBICOM32_ARCH_VERSION, pn->arch_version); + proc_node_valid = 0; + } + + if (proc_node_valid) + return; +error: + processor_validate_failed(); +} + +void __init processor_init(void) +{ + /* + * If we do not have a trap node in the device tree, we leave the fault + * handling to the underlying hardware. + */ + pn = (struct procnode *)devtree_find_node("processor"); + + processor_validate(); + + /* + * If necessary correct the initial range registers to cover the + * complete physical space + */ + if (pn->edram > (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE)) { + printk(KERN_INFO "updating range registers for expanded dram\n"); + asm volatile ( + " move.4 D_RANGE1_HI, %0 \t\n" + " move.4 I_RANGE0_HI, %0 \t\n" +#ifdef CONFIG_PROTECT_KERNEL + " move.4 D_RANGE2_HI, %0 \t\n" + " move.4 I_RANGE2_HI, %0 \t\n" +#endif + : : "a"((unsigned long)pn->edram - 4) + ); + } + +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c new file mode 100644 index 000000000..18bb39e9d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c @@ -0,0 +1,275 @@ +/* + * arch/ubicom32/kernel/ptrace.c + * Ubicom32 architecture ptrace implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * ptrace_getregs() + * + * Get all user integer registers. + */ +static inline int ptrace_getregs(struct task_struct *task, void __user *uregs) +{ + struct pt_regs *regs = task_pt_regs(task); + return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; +} + +/* + * ptrace_get_reg() + * + * Get contents of register REGNO in task TASK. + */ +static unsigned long ptrace_get_reg(struct task_struct *task, int regno) +{ + if (regno < sizeof(struct pt_regs)) { + struct pt_regs *pt_regs = task_pt_regs(task); + return *(unsigned long *)((long) pt_regs + regno); + } + + return -EIO; +} + +/* + * ptrace_put_reg() + * Write contents of register REGNO in task TASK. + */ +static int ptrace_put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + if (regno <= sizeof(struct pt_regs) && regno != PT_FRAME_TYPE) { + struct pt_regs *pt_regs = task_pt_regs(task); + *(unsigned long *)((long) pt_regs + regno) = data; + return 0; + } + return -EIO; +} + +/* + * ptrace_disable_single_step() + * Disable Single Step + */ +static int ptrace_disable_single_step(struct task_struct *task) +{ + /* + * Single Step not yet implemented, so must always be disabled + */ + return 0; +} + +/* + * ptrace_disable() + * Make sure the single step bit is not set. + * Called by kernel/ptrace.c when detaching.. + */ +void ptrace_disable(struct task_struct *child) +{ + ptrace_disable_single_step(child); +} + +/* + * arch_ptrace() + * architecture specific ptrace routine. + */ +long arch_ptrace(struct task_struct *child, long request, long addr, long data) +{ + int ret; + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: + ret = generic_ptrace_peekdata(child, addr, data); + break; + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP) + || (addr & 3)) + break; + + tmp = 0; /* Default return condition */ + + ret = -EIO; + if (addr < sizeof(struct pt_regs)) { + tmp = ptrace_get_reg(child, addr); + } else if (addr == PT_TEXT_ADDR) { + tmp = child->mm->start_code; + } else if (addr == PT_TEXT_END_ADDR) { + tmp = child->mm->end_code; + } else if (addr == PT_DATA_ADDR) { + tmp = child->mm->start_data; + } else if (addr == PT_EXEC_FDPIC_LOADMAP) { +#ifdef CONFIG_BINFMT_ELF_FDPIC + tmp = child->mm->context.exec_fdpic_loadmap; +#endif + } else if (addr == PT_INTERP_FDPIC_LOADMAP) { +#ifdef CONFIG_BINFMT_ELF_FDPIC + tmp = child->mm->context.interp_fdpic_loadmap; +#endif + } else { + break; + } + + ret = put_user(tmp, (unsigned long *)data); + break; + } + + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = generic_ptrace_pokedata(child, addr, data); + + /* + * If we just changed some code so we need to + * correct the caches + */ + if (request == PTRACE_POKETEXT && ret == 0) { + flush_icache_range(addr, addr + 4); + } + break; + + case PTRACE_POKEUSR: /* write the word at location addr + * in the USER area */ + ret = -EIO; + + if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3)) + break; + + if (addr < sizeof(struct pt_regs)) { + ret = ptrace_put_reg(child, addr, data); + } + break; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) + * syscall */ + case PTRACE_CONT: { /* restart after signal. */ + + ret = -EIO; + if (!valid_signal(data)) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + /* make sure the single step bit is not set. */ + ptrace_disable_single_step(child); + wake_up_process(child); + ret = 0; + break; + } + + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to exit. + */ + case PTRACE_KILL: { + ret = 0; + if (child->exit_state == EXIT_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + ptrace_disable_single_step(child); + wake_up_process(child); + break; + } + + case PTRACE_DETACH: /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + break; + + case PTRACE_GETREGS: /* Get all gp regs from the child. */ + ptrace_getregs(child, (unsigned long *)data); + ret = 0; + break; + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + int i; + unsigned long tmp; + int count = sizeof(struct pt_regs) / sizeof(unsigned long); + for (i = 0; i < count; i++) { + if (get_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + break; + } + ptrace_put_reg(child, sizeof(unsigned long) * i, tmp); + data += sizeof(long); + } + ret = 0; + break; + } + + default: + return ptrace_request(child, request, addr, data); + break; + } + return ret; +} +/* + * syscall_trace + * + * called by syscall enter/exit when the TIF_SYSCALL_TRACE bit is set. + */ +asmlinkage void syscall_trace(void) +{ + struct task_struct *cur = current; + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(cur->ptrace & PT_PTRACED)) + return; + ptrace_notify(SIGTRAP | ((cur->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (cur->exit_code) { + send_sig(cur->exit_code, current, 1); + current->exit_code = 0; + } +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/semaphore.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/semaphore.c new file mode 100644 index 000000000..d996ac2b3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/semaphore.c @@ -0,0 +1,159 @@ +/* + * arch/ubicom32/kernel/semaphore.c + * Ubicom32 architecture semaphore implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include +#include +#include + +#ifndef CONFIG_RMW_INSNS +spinlock_t semaphore_wake_lock; +#endif + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + + +#define DOWN_HEAD(task_state) \ + \ + \ + current->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + current->state = (task_state); \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __sched __down(struct semaphore *sem) +{ + DECLARE_WAITQUEUE(wait, current); + + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __sched __down_interruptible(struct semaphore *sem) +{ + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, current); + if (ret) { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore *sem) +{ + return waking_non_zero_trylock(sem); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/setup.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/setup.c new file mode 100644 index 000000000..7357f4ee3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/setup.c @@ -0,0 +1,194 @@ +/* + * arch/ubicom32/kernel/setup.c + * Ubicom32 architecture-dependent parts of system setup. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1999-2007 Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998,1999 D. Jeff Dionne + * Copyleft ()) 2000 James D. Schettine {james@telos-systems.com} + * Copyright (C) 1998 Kenneth Albanowski + * Copyright (C) 1995 Hamish Macdonald + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * Copyright (C) 2001 Lineo, Inc. + * 68VZ328 Fixes/support Evan Stawnyczy + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned long memory_start; +EXPORT_SYMBOL(memory_start); + +unsigned long memory_end; +EXPORT_SYMBOL(memory_end); + +static char __initdata command_line[COMMAND_LINE_SIZE]; +#ifdef CONFIG_CMDLINE_BOOL +static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; +#endif + +extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; + +/* + * setup_arch() + * Setup the architecture dependent portions of the system. + */ +void __init setup_arch(char **cmdline_p) +{ + int bootmap_size; + unsigned long ram_start; + + processor_init(); + bootargs_init(); + + /* + * Use the link for memory_start from the link and the processor + * node for memory_end. + */ + memory_start = PAGE_ALIGN(((unsigned long)&_end)); + processor_dram(&ram_start, &memory_end); + + init_mm.start_code = (unsigned long) &_stext; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) 0; + + /* + * bootexec copies the original default command line to end of memory. + * u-boot can modify it there (i.e. to enable network boot) and the + * kernel picks up the modified version. + * + * mainexec creates a `new default' command_line which is in the + * bootargs devnode. It is updated on every firmware update but + * not used at the moment. + */ + strlcpy(boot_command_line, (char *)(memory_end - COMMAND_LINE_SIZE), COMMAND_LINE_SIZE); + +#ifdef CONFIG_CMDLINE_BOOL +#ifdef CONFIG_CMDLINE_OVERRIDE + strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); +#else + if (builtin_cmdline[0]) { + /* append boot loader cmdline to builtin */ + strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE); + strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE); + strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); + } +#endif +#endif + + strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); + *cmdline_p = command_line; + + parse_early_param(); + + printk(KERN_INFO "%s Processor, Ubicom, Inc. \n", CPU); + +#if defined(DEBUG) + printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x " + "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext, + (int) &_sdata, (int) &_edata, + (int) &_sbss, (int) &_ebss); + printk(KERN_DEBUG "MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ", + (int) &_ebss, (int) memory_start, + (int) memory_start, (int) memory_end); +#endif + +#ifdef DEBUG + if (strlen(*cmdline_p)) + printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p); +#endif + +#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif + + /* + * If we have a device tree, see if we have the nodes we need. + */ + if (devtree) { + devtree_print(); + } + + /* + * From the arm initialization comment: + * + * This doesn't seem to be used by the Linux memory manager any + * more, but is used by ll_rw_block. If we can get rid of it, we + * also get rid of some of the stuff above as well. + * + * Note: max_low_pfn and max_pfn reflect the number of _pages_ in + * the system, not the maximum PFN. + */ + max_pfn = max_low_pfn = (memory_end - PAGE_OFFSET) >> PAGE_SHIFT; + + /* + * Give all the memory to the bootmap allocator, tell it to put the + * boot mem_map at the start of memory. + */ + bootmap_size = init_bootmem_node( + NODE_DATA(0), + memory_start >> PAGE_SHIFT, /* map goes here */ + PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */ + memory_end >> PAGE_SHIFT); + /* + * Free the usable memory, we have to make sure we do not free + * the bootmem bitmap so we then reserve it after freeing it :-) + */ + free_bootmem(memory_start, memory_end - memory_start); + reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT); + + /* + * Get kmalloc into gear. + */ + paging_init(); + + /* + * Fix up the thread_info structure, indicate this is a mainline Linux + * thread and setup the sw_ksp(). + */ + sw_ksp[thread_get_self()] = (unsigned int) current_thread_info(); + thread_set_mainline(thread_get_self()); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c new file mode 100644 index 000000000..f6ccbe3a7 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c @@ -0,0 +1,458 @@ +/* + * arch/ubicom32/kernel/signal.c + * Ubicom32 architecture signal handling implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1991, 1992 Linus Torvalds + * Linux/m68k support by Hamish Macdonald + * 68060 fixes by Jesper Skov + * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab + * mathemu support by Roman Zippel + * ++roman (07/09/96): implemented signal stacks + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * + * mathemu support by Roman Zippel + * (Note: fpstate in the signal context is completely ignored for the emulator + * and the internal floating point format is put on stack) + * + * ++roman (07/09/96): implemented signal stacks (specially for tosemu on + * Atari :-) Current limitation: Only one sigstack can be active at one time. + * If a second signal with SA_ONSTACK set arrives while working on a sigstack, + * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested + * signal handlers! + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +/* + * asm signal return handlers. + */ +void ret_from_user_signal(void); +void ret_from_user_rt_signal(void); +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); + +/* + * Common signal suspend implementation + */ +static int signal_suspend(sigset_t *saveset, struct pt_regs *regs) +{ + regs->dn[0] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (!do_signal(saveset, regs)) { + continue; + } + /* + * If the current frame type is a signal trampoline we are + * actually going to call the signal handler so we return the + * desired d0 as the return value. + */ + if (regs->frame_type == UBICOM32_FRAME_TYPE_SIGTRAMP) { + return regs->dn[0]; + } + return -EINTR; + } + /* + * Should never get here + */ + BUG(); + return 0; +} + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int do_sigsuspend(struct pt_regs *regs) +{ + old_sigset_t mask = regs->dn[0]; + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + /* + * Call common handler + */ + return signal_suspend(&saveset, regs); +} + +asmlinkage int +do_rt_sigsuspend(struct pt_regs *regs) +{ + sigset_t *unewset = (sigset_t *)regs->dn[0]; + size_t sigsetsize = (size_t)regs->dn[1]; + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + /* + * Call common handler + */ + return signal_suspend(&saveset, regs); +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (!access_ok(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage int +do_sys_sigaltstack(struct pt_regs *regs) +{ + const stack_t *uss = (stack_t *) regs->dn[0]; + stack_t *uoss = (stack_t *)regs->dn[1]; + return do_sigaltstack(uss, uoss, regs->an[7]); +} + +/* + * fdpic_func_descriptor describes sa_handler when the application is FDPIC + */ +struct fdpic_func_descriptor { + unsigned long text; + unsigned long GOT; +}; + +/* + * rt_sigframe is stored on the user stack immediately before (above) + * the signal handlers stack. + */ +struct rt_sigframe +{ + unsigned long syscall_number; /* This holds __NR_rt_sigreturn. */ + unsigned long restore_all_regs; /* This field gets set to 1 if the frame + * type is TRAP or INTERRUPT. */ + siginfo_t *info; + struct ucontext uc; + int sig; + void *pretcode; +}; + +/* + * Do a signal return; undo the signal stack. + */ +asmlinkage int do_sigreturn(unsigned long __unused) +{ + BUG(); + return 0; +} + +asmlinkage int do_rt_sigreturn(struct pt_regs *regs) +{ + unsigned long usp = regs->an[7]; + struct rt_sigframe *frame = (struct rt_sigframe *)(usp); + sigset_t set; + + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (copy_from_user(regs, &frame->uc.uc_mcontext, sizeof(struct pt_regs))) + goto badframe; + return regs->dn[0]; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + unsigned long usp; + + /* Default to using normal stack. */ + usp = regs->an[7]; + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (!sas_ss_flags(usp)) + usp = current->sas_ss_sp + current->sas_ss_size; + } + return (void *)((usp - frame_size) & ~0x3); +} + +/* + * signal_trampoline: Defined in ubicom32_syscall.S + */ +asmlinkage void signal_trampoline(void)__attribute__((naked)); + +static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int err = 0; + + frame = (struct rt_sigframe *) get_sigframe(ka, regs, sizeof(*frame)); + + /* + * The 'err |=' have been may criticized as bad code style, but I + * strongly suspect that we want this code to be fast. So for + * now it stays as is. + */ + err |= __put_user( ( (current_thread_info()->exec_domain) + && (current_thread_info()->exec_domain->signal_invmap) + && (sig < 32) ) + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig, &frame->sig); + err |= __put_user(info, &frame->info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user((void *)current->sas_ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->an[7]), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= __put_user(__NR_rt_sigreturn, &frame->syscall_number); + if ((regs->frame_type == UBICOM32_FRAME_TYPE_TRAP) || + (regs->frame_type == UBICOM32_FRAME_TYPE_INTERRUPT)) { + err |= __put_user(1, &frame->restore_all_regs); + } else { + err |= __put_user(0, &frame->restore_all_regs); + } + err |= copy_to_user (&frame->uc.uc_mcontext.sc_regs, regs, sizeof(struct pt_regs)); + err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); + + if (err) + goto give_sigsegv; + + /* + * Set up registers for signal handler NOTE: Do not modify dn[14], it + * contains the userspace tls pointer, so it important that it carries + * over to the signal handler. + */ + regs->an[7] = (unsigned long)frame; + regs->pc = (unsigned long) signal_trampoline; + regs->an[5] = (unsigned long) signal_trampoline; + regs->dn[0] = sig; + regs->dn[1] = (unsigned long) frame->info; + regs->dn[2] = (unsigned int) &frame->uc; + + /* + * If this is FDPIC then the signal handler is actually a function + * descriptor. + */ + if (current->personality & FDPIC_FUNCPTRS) { + struct fdpic_func_descriptor __user *funcptr = + (struct fdpic_func_descriptor *) ka->sa.sa_handler; + err |= __get_user(regs->dn[3], &funcptr->text); + err |= __get_user(regs->an[0], &funcptr->GOT); + if (err) + goto give_sigsegv; + + /* + * The funcdesc must be in a3 as this is required for the lazy + * resolver in ld.so, if the application is not FDPIC a3 is not + * used. + */ + regs->an[3] = (unsigned long) funcptr; + + } else { + regs->dn[3] = (unsigned long)ka->sa.sa_handler; + regs->an[0] = 0; + } + + regs->frame_type = UBICOM32_FRAME_TYPE_SIGTRAMP; + + return; + +give_sigsegv: + /* user space exception */ + force_sigsegv(sig, current); +} + +static inline void +handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) +{ + switch (regs->dn[0]) { + case -ERESTARTNOHAND: + if (!has_handler) + goto do_restart; + regs->dn[0] = -EINTR; + break; + + case -ERESTARTSYS: + if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { + regs->dn[0] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + do_restart: + regs->dn[0] = regs->original_dn_0; + regs->pc -= 8; + regs->an[5] -= 8; + break; + } +} + +/* + * OK, we're invoking a handler + */ +static void +handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) +{ + /* are we from a system call? */ + if (regs->frame_type == -1) + /* If so, check system call restarting.. */ + handle_restart(regs, ka, 1); + + /* set up the stack frame */ + setup_rt_frame(sig, ka, info, oldset, regs); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + */ +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +{ + struct k_sigaction ka; + siginfo_t info; + int signr; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 1; + + if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + if (signr > 0) { + /* Whee! Actually deliver the signal. */ + handle_signal(signr, &ka, &info, oldset, regs); + return 1; + } + + /* Did we come from a system call? */ + if (regs->frame_type == -1) { + /* Restart the system call - no handlers present */ + handle_restart(regs, NULL, 0); + } + + return 0; +} + +/* + * sys_sigreturn() + * Return handler for signal clean-up. + * + * NOTE: Ubicom32 does not use this syscall. Instead we rely + * on do_rt_sigreturn(). + */ +asmlinkage long sys_sigreturn(void) +{ + return -ENOSYS; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c new file mode 100644 index 000000000..4aa27eb44 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c @@ -0,0 +1,806 @@ +/* + * arch/ubicom32/kernel/smp.c + * SMP implementation for Ubicom32 processors. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 2001,2004 Grant Grundler + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Mask the debug printout for IPI because they are too verbose + * for regular debugging. + */ + +// #define DEBUG_SMP 1 +#if !defined(DEBUG_SMP) +#define smp_debug(lvl, ...) +#else +static unsigned int smp_debug_lvl = 50; +#define smp_debug(lvl, printargs...) \ + if (lvl >= smp_debug_lvl) { \ + printk(printargs); \ + } +#endif + +#if !defined(DEBUG_SMP) +#define DEBUG_ASSERT(cond) +#else +#define DEBUG_ASSERT(cond) \ + if (!(cond)) { \ + THREAD_STALL; \ + } +#endif + +/* + * List of IPI Commands (more than one can be set at a time). + */ +enum ipi_message_type { + IPI_NOP, + IPI_RESCHEDULE, + IPI_CALL_FUNC, + IPI_CALL_FUNC_SINGLE, + IPI_CPU_STOP, + IPI_CPU_TIMER, +}; + +/* + * We maintain a hardware thread oriented view of online threads + * and those involved or needing IPI. + */ +static volatile unsigned long smp_online_threads = 0; +static volatile unsigned long smp_needs_ipi = 0; +static volatile unsigned long smp_inside_ipi = 0; +static unsigned long smp_irq_affinity[NR_IRQS]; + +/* + * What do we need to track on a per cpu/thread basis? + */ +DEFINE_PER_CPU(struct cpuinfo_ubicom32, cpu_data); + +/* + * Each thread cpuinfo IPI information is guarded by a lock + * that is kept local to this file. + */ +DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED; + +/* + * The IPI(s) are based on a software IRQ through the LDSR. + */ +unsigned int smp_ipi_irq; + +/* + * Define a spinlock so that only one cpu is able to modify the + * smp_needs_ipi and to set/clear the IRQ at a time. + */ +DEFINE_SPINLOCK(smp_ipi_lock); + +/* + * smp_halt_processor() + * Halt this hardware thread. + */ +static void smp_halt_processor(void) +{ + int cpuid = thread_get_self(); + cpu_clear(smp_processor_id(), cpu_online_map); + local_irq_disable(); + printk(KERN_EMERG "cpu[%d] has halted. It is not OK to turn off power \ + until all cpu's are off.\n", cpuid); + for (;;) { + thread_suspend(); + } +} + +/* + * ipi_interrupt() + * Handle an Interprocessor Interrupt. + */ +static irqreturn_t ipi_interrupt(int irq, void *dev_id) +{ + int cpuid = smp_processor_id(); + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid); + unsigned long ops; + + /* + * Count this now; we may make a call that never returns. + */ + p->ipi_count++; + + /* + * We are about to process all ops. If another cpu has stated + * that we need an IPI, we will have already processed it. By + * clearing our smp_needs_ipi, and processing all ops, + * we reduce the number of IPI interrupts. However, this introduces + * the possibility that smp_needs_ipi will be clear and the soft irq + * will have gone off; so we need to make the get_affinity() path + * tolerant of spurious interrupts. + */ + spin_lock(&smp_ipi_lock); + smp_needs_ipi &= ~(1 << p->tid); + spin_unlock(&smp_ipi_lock); + + for (;;) { + /* + * Read the set of IPI commands we should handle. + */ + spinlock_t *lock = &per_cpu(ipi_lock, cpuid); + spin_lock(lock); + ops = p->ipi_pending; + p->ipi_pending = 0; + spin_unlock(lock); + + /* + * If we have no IPI commands to execute, break out. + */ + if (!ops) { + break; + } + + /* + * Execute the set of commands in the ops word, one command + * at a time in no particular order. Strip of each command + * as we execute it. + */ + while (ops) { + unsigned long which = ffz(~ops); + ops &= ~(1 << which); + + BUG_ON(!irqs_disabled()); + switch (which) { + case IPI_NOP: + smp_debug(100, KERN_INFO "cpu[%d]: " + "IPI_NOP\n", cpuid); + break; + + case IPI_RESCHEDULE: + /* + * Reschedule callback. Everything to be + * done is done by the interrupt return path. + */ + smp_debug(200, KERN_INFO "cpu[%d]: " + "IPI_RESCHEDULE\n", cpuid); + break; + + case IPI_CALL_FUNC: + smp_debug(100, KERN_INFO "cpu[%d]: " + "IPI_CALL_FUNC\n", cpuid); + generic_smp_call_function_interrupt(); + break; + + case IPI_CALL_FUNC_SINGLE: + smp_debug(100, KERN_INFO "cpu[%d]: " + "IPI_CALL_FUNC_SINGLE\n", cpuid); + generic_smp_call_function_single_interrupt(); + break; + + case IPI_CPU_STOP: + smp_debug(100, KERN_INFO "cpu[%d]: " + "IPI_CPU_STOP\n", cpuid); + smp_halt_processor(); + break; + +#if !defined(CONFIG_LOCAL_TIMERS) + case IPI_CPU_TIMER: + smp_debug(100, KERN_INFO "cpu[%d]: " + "IPI_CPU_TIMER\n", cpuid); +#if defined(CONFIG_GENERIC_CLOCKEVENTS) + local_timer_interrupt(); +#else + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); +#endif +#endif + break; + + default: + printk(KERN_CRIT "cpu[%d]: " + "Unknown IPI: %lu\n", cpuid, which); + + return IRQ_NONE; + } + + /* + * Let in any pending interrupts + */ + BUG_ON(!irqs_disabled()); + local_irq_enable(); + local_irq_disable(); + } + } + return IRQ_HANDLED; +} + +/* + * ipi_send() + * Send an Interprocessor Interrupt. + */ +static void ipi_send(int cpu, enum ipi_message_type op) +{ + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu); + spinlock_t *lock = &per_cpu(ipi_lock, cpu); + unsigned long flags; + + /* + * We protect the setting of the ipi_pending field and ensure + * that the ipi delivery mechanism and interrupt are atomically + * handled. + */ + spin_lock_irqsave(lock, flags); + p->ipi_pending |= 1 << op; + spin_unlock_irqrestore(lock, flags); + + spin_lock_irqsave(&smp_ipi_lock, flags); + smp_needs_ipi |= (1 << p->tid); + ubicom32_set_interrupt(smp_ipi_irq); + spin_unlock_irqrestore(&smp_ipi_lock, flags); + smp_debug(100, KERN_INFO "cpu[%d]: send: %d\n", cpu, op); +} + +/* + * ipi_send_mask + * Send an IPI to each cpu in mask. + */ +static inline void ipi_send_mask(unsigned int op, const struct cpumask mask) +{ + int cpu; + for_each_cpu_mask(cpu, mask) { + ipi_send(cpu, op); + } +} + +/* + * ipi_send_allbutself() + * Send an IPI to all threads but ourselves. + */ +static inline void ipi_send_allbutself(unsigned int op) +{ + int self = smp_processor_id(); + struct cpumask result; + cpumask_copy(&result, &cpu_online_map); + cpu_clear(self, result); + ipi_send_mask(op, result); +} + +/* + * smp_enable_vector() + */ +static void smp_enable_vector(unsigned int irq) +{ + ubicom32_clear_interrupt(smp_ipi_irq); + ldsr_enable_vector(irq); +} + +/* + * smp_disable_vector() + * Disable the interrupt by clearing the appropriate bit in the + * LDSR Mask Register. + */ +static void smp_disable_vector(unsigned int irq) +{ + ldsr_disable_vector(irq); +} + +/* + * smp_mask_vector() + */ +static void smp_mask_vector(unsigned int irq) +{ + ldsr_mask_vector(irq); +} + +/* + * smp_unmask_vector() + */ +static void smp_unmask_vector(unsigned int irq) +{ + ldsr_unmask_vector(irq); +} + +/* + * smp_end_vector() + * Called once an interrupt is completed (reset the LDSR mask). + */ +static void smp_end_vector(unsigned int irq) +{ + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, smp_processor_id()); + spin_lock(&smp_ipi_lock); + smp_inside_ipi &= ~(1 << p->tid); + if (smp_inside_ipi) { + spin_unlock(&smp_ipi_lock); + return; + } + spin_unlock(&smp_ipi_lock); + ldsr_unmask_vector(irq); + smp_debug(100, KERN_INFO "cpu[%d]: unamesk vector\n", smp_processor_id()); +} + +/* + * Special hanlder functions for SMP. + */ +static struct irq_chip ubicom32_smp_chip = { + .name = "UbicoIPI", + .startup = NULL, + .shutdown = NULL, + .enable = smp_enable_vector, + .disable = smp_disable_vector, + .ack = NULL, + .mask = smp_mask_vector, + .unmask = smp_unmask_vector, + .end = smp_end_vector, +}; + +/* + * smp_reset_ipi() + * None of these cpu(s) got their IPI, turn it back on. + * + * Note: This is called by the LDSR which is not a full + * Linux cpu. Thus you must use the raw form of locks + * because lock debugging will not work on the partial + * cpu nature of the LDSR. + */ +void smp_reset_ipi(unsigned long mask) +{ + __raw_spin_lock(&smp_ipi_lock.raw_lock); + smp_needs_ipi |= mask; + smp_inside_ipi &= ~mask; + ubicom32_set_interrupt(smp_ipi_irq); + __raw_spin_unlock(&smp_ipi_lock.raw_lock); + smp_debug(100, KERN_INFO "smp: reset IPIs for: 0x%x\n", mask); +} + +/* + * smp_get_affinity() + * Choose the thread affinity for this interrupt. + * + * Note: This is called by the LDSR which is not a full + * Linux cpu. Thus you must use the raw form of locks + * because lock debugging will not work on the partial + * cpu nature of the LDSR. + */ +unsigned long smp_get_affinity(unsigned int irq, int *all) +{ + unsigned long mask = 0; + + /* + * Most IRQ(s) are delivered in a round robin fashion. + */ + if (irq != smp_ipi_irq) { + unsigned long result = smp_irq_affinity[irq] & smp_online_threads; + DEBUG_ASSERT(result); + *all = 0; + return result; + } + + /* + * This is an IPI request. Return all cpu(s) scheduled for an IPI. + * We also track those cpu(s) that are going to be "receiving" IPI this + * round. When all CPU(s) have called smp_end_vector(), + * we will unmask the IPI interrupt. + */ + __raw_spin_lock(&smp_ipi_lock.raw_lock); + ubicom32_clear_interrupt(smp_ipi_irq); + if (smp_needs_ipi) { + mask = smp_needs_ipi; + smp_inside_ipi |= smp_needs_ipi; + smp_needs_ipi = 0; + } + __raw_spin_unlock(&smp_ipi_lock.raw_lock); + *all = 1; + return mask; +} + +/* + * smp_set_affinity() + * Set the affinity for this irq but store the value in tid(s). + */ +void smp_set_affinity(unsigned int irq, const struct cpumask *dest) +{ + int cpuid; + unsigned long *paffinity = &smp_irq_affinity[irq]; + + /* + * If none specified, all cpus are allowed. + */ + if (cpus_empty(*dest)) { + *paffinity = 0xffffffff; + return; + } + + /* + * Make sure to clear the old value before setting up the + * list. + */ + *paffinity = 0; + for_each_cpu_mask(cpuid, *dest) { + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid); + *paffinity |= (1 << p->tid); + } +} + +/* + * smp_send_stop() + * Send a stop request to all CPU but this one. + */ +void smp_send_stop(void) +{ + ipi_send_allbutself(IPI_CPU_STOP); +} + +/* + * smp_send_timer_all() + * Send all cpu(s) but this one, a request to update times. + */ +void smp_send_timer_all(void) +{ + ipi_send_allbutself(IPI_CPU_TIMER); +} + +/* + * smp_timer_broadcast() + * Use an IPI to broadcast a timer message + */ +void smp_timer_broadcast(const struct cpumask *mask) +{ + ipi_send_mask(IPI_CPU_TIMER, *mask); +} + +/* + * smp_send_reschedule() + * Send a reschedule request to the specified cpu. + */ +void smp_send_reschedule(int cpu) +{ + ipi_send(cpu, IPI_RESCHEDULE); +} + +/* + * arch_send_call_function_ipi() + * Cause each cpu in the mask to call the generic function handler. + */ +void arch_send_call_function_ipi_mask(const struct cpumask *mask) +{ + int cpu; + for_each_cpu_mask(cpu, *mask) { + ipi_send(cpu, IPI_CALL_FUNC); + } +} + +/* + * arch_send_call_function_single_ipi() + * Cause the specified cpu to call the generic function handler. + */ +void arch_send_call_function_single_ipi(int cpu) +{ + ipi_send(cpu, IPI_CALL_FUNC_SINGLE); +} + +/* + * setup_profiling_timer() + * Dummy function created to keep Oprofile happy in the SMP case. + */ +int setup_profiling_timer(unsigned int multiplier) +{ + return 0; +} + +/* + * smp_mainline_start() + * Start a slave thread executing a mainline Linux context. + */ +static void __init smp_mainline_start(void *arg) +{ + int cpuid = smp_processor_id(); + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid); + + BUG_ON(p->tid != thread_get_self()); + + /* + * Well, support 2.4 linux scheme as well. + */ + if (cpu_test_and_set(cpuid, cpu_online_map)) { + printk(KERN_CRIT "cpu[%d]: already initialized!\n", cpuid); + smp_halt_processor(); + return; + } + + /* + * Initialise the idle task for this CPU + */ + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + if (current->mm) { + printk(KERN_CRIT "cpu[%d]: idle task already has memory " + "management\n", cpuid); + smp_halt_processor(); + return; + } + + /* + * TODO: X86 does this prior to calling notify, try to understand why? + */ + preempt_disable(); + +#if defined(CONFIG_GENERIC_CLOCKEVENTS) + /* + * Setup a local timer event so that this cpu will get timer interrupts + */ + if (local_timer_setup(cpuid) == -1) { + printk(KERN_CRIT "cpu[%d]: timer alloc failed\n", cpuid); + smp_halt_processor(); + return; + } +#endif + + /* + * Notify those interested that we are up and alive. This must + * be done before interrupts are enabled. It must also be completed + * before the bootstrap cpu returns from __cpu_up() (see comment + * above cpu_set() of the cpu_online_map). + */ + notify_cpu_starting(cpuid); + + /* + * Indicate that this thread is now online and present. Setting + * cpu_online_map has the side effect of allowing the bootstrap + * cpu to continue along; so anything that MUST be done prior to the + * bootstrap cpu returning from __cpu_up() needs to go above here. + */ + cpu_set(cpuid, cpu_online_map); + cpu_set(cpuid, cpu_present_map); + + /* + * Maintain a thread mapping in addition to the cpu mapping. + */ + smp_online_threads |= (1 << p->tid); + + /* + * Enable interrupts for this thread. + */ + local_irq_enable(); + + /* + * Enter the idle loop and wait for a timer to schedule some work. + */ + printk(KERN_INFO "cpu[%d]: entering cpu_idle()\n", cpuid); + cpu_idle(); + + /* Not Reached */ +} + +/* + * smp_cpus_done() + * Called once the kernel_init() has brought up all cpu(s). + */ +void smp_cpus_done(unsigned int cpu_max) +{ + /* Do Nothing */ +} + +/* + * __cpu_up() + * Called to startup a sepcific cpu. + */ +int __cpuinit __cpu_up(unsigned int cpu) +{ + struct task_struct *idle; + unsigned int *stack; + long timeout; + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu); + + /* + * Create an idle task for this CPU. + */ + idle = fork_idle(cpu); + if (IS_ERR(idle)) { + panic("cpu[%d]: fork failed\n", cpu); + return -ENOSYS; + } + task_thread_info(idle)->cpu = cpu; + + /* + * Setup the sw_ksp[] to point to this new task. + */ + sw_ksp[p->tid] = (unsigned int)idle->stack; + stack = (unsigned int *)(sw_ksp[p->tid] + PAGE_SIZE - 8); + + /* + * Cause the specified thread to execute our smp_mainline_start + * function as a TYPE_NORMAL thread. + */ + printk(KERN_INFO "cpu[%d]: launching mainline Linux thread\n", cpu); + if (thread_start(p->tid, smp_mainline_start, (void *)NULL, stack, + THREAD_TYPE_NORMAL) == -1) { + printk(KERN_WARNING "cpu[%d]: failed thread_start\n", cpu); + return -ENOSYS; + } + + /* + * Wait for the thread to start up. The thread will set + * the online bit when it is running. Our caller execpts the + * cpu to be online if we return 0. + */ + for (timeout = 0; timeout < 10000; timeout++) { + if (cpu_online(cpu)) { + break; + } + + udelay(100); + barrier(); + continue; + } + + if (!cpu_online(cpu)) { + printk(KERN_CRIT "cpu[%d]: failed to live after %ld us\n", + cpu, timeout * 100); + return -ENOSYS; + } + + printk(KERN_INFO "cpu[%d]: came alive after %ld us\n", + cpu, timeout * 100); + return 0; +} + +/* + * Data used by setup_irq for the IPI. + */ +static struct irqaction ipi_irq = { + .name = "ipi", + .flags = IRQF_DISABLED | IRQF_PERCPU, + .handler = ipi_interrupt, +}; + +/* + * smp_prepare_cpus() + * Mark threads that are available to Linux as possible cpus(s). + */ +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + int i; + + /* + * We will need a software IRQ to send IPI(s). We will use + * a single software IRQ for all IPI(s). + */ + if (irq_soft_alloc(&smp_ipi_irq) < 0) { + panic("no software IRQ is available\n"); + return; + } + + /* + * For the IPI interrupt, we want to use our own chip definition. + * This allows us to define what happens in SMP IPI without affecting + * the performance of the other interrupts. + * + * Next, Register the IPI interrupt function against the soft IRQ. + */ + set_irq_chip(smp_ipi_irq, &ubicom32_smp_chip); + setup_irq(smp_ipi_irq, &ipi_irq); + + /* + * We use the device tree node to determine how many + * free cpus we will have (up to NR_CPUS) and we indicate + * that those cpus are present. + * + * We need to do this very early in the SMP case + * because the Linux init code uses the cpu_present_map. + */ + for_each_possible_cpu(i) { + thread_t tid; + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, i); + + /* + * Skip the bootstrap cpu + */ + if (i == 0) { + continue; + } + + /* + * If we have a free thread left in the mask, + * indicate that the cpu is present. + */ + tid = thread_alloc(); + if (tid == (thread_t)-1) { + break; + } + + /* + * Save the hardware thread id for this cpu. + */ + p->tid = tid; + cpu_set(i, cpu_present_map); + printk(KERN_INFO "cpu[%d]: added to cpu_present_map - tid: %d\n", i, tid); + } +} + +/* + * smp_prepare_boot_cpu() + * Copy the per_cpu data into the appropriate spot for the bootstrap cpu. + * + * The code in boot_cpu_init() has already set the boot cpu's + * state in the possible, present, and online maps. + */ +void __devinit smp_prepare_boot_cpu(void) +{ + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0); + + smp_online_threads |= (1 << p->tid); + printk(KERN_INFO "cpu[%d]: bootstrap CPU online - tid: %ld\n", + current_thread_info()->cpu, p->tid); +} + +/* + * smp_setup_processor_id() + * Set the current_thread_info() structure cpu value. + * + * We set the value to the true hardware thread value that we are running on. + * NOTE: this function overrides the weak alias function in main.c + */ +void __init smp_setup_processor_id(void) +{ + struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0); + int i; + for_each_cpu_mask(i, CPU_MASK_ALL) + set_cpu_possible(i, true); + + current_thread_info()->cpu = 0; + p->tid = thread_get_self(); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/stacktrace.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/stacktrace.c new file mode 100644 index 000000000..2a10e3f4f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/stacktrace.c @@ -0,0 +1,244 @@ +/* + * arch/ubicom32/kernel/stacktrace.c + * Ubicom32 architecture stack back trace implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include + +/* + * These symbols are filled in by the linker. + */ +extern unsigned long _stext; +extern unsigned long _etext; + +extern unsigned long __ocm_text_run_begin; +extern unsigned long __data_begin; + +/* + * stacktrace_iterate() + * Walk the stack looking for call and calli instructions on an aligned + * boundary. + * + * Trace must point to the top of the current stack frame. + */ +unsigned long stacktrace_iterate(unsigned long **trace, + unsigned long stext, + unsigned long etext, + unsigned long ocm_stext, + unsigned long ocm_etext, + unsigned long sstack, + unsigned long estack) +{ + unsigned int thread_trap_en, instruction; + unsigned long address; + unsigned int limit = 0; + unsigned long result = 0; + unsigned long *sp = *trace; + + /* + * Exclude the current thread from being monitored for traps. + */ + asm volatile( + " thread_get_self_mask d15 \n\t" + /* save current trap status */ + " and.4 %0, MT_TRAP_EN, d15 \n\t" + " not.4 d15, d15 \n\t" + /* disable trap */ + " and.4 MT_TRAP_EN, MT_TRAP_EN, d15 \n\t" + " pipe_flush 0 \n\t" + : "=r" (thread_trap_en) + : + : "d15", "cc" + ); + + while (limit++ < 256) { + /* + * See if we have a valid stack. + */ + if (!between((unsigned long)sp, sstack, estack)) { +#ifdef TRAP_DEBUG_STACK_TRACE + printk(KERN_EMERG "stack address is out of range - " + "sp: %x, sstack: %x, estack: %x\n", + (unsigned int)sp, (unsigned int)sstack, + (unsigned int)estack); +#endif + result = 0; + *trace = 0; + break; + } + + /* + * Get the value off the stack and back up 4 bytes to what + * should be the address of a call or calli. + */ + address = (*sp++) - 4; + + /* + * If the address is not within the text segment, skip this + * value. + */ + if (!between(address, stext, etext) && + !between(address, ocm_stext, ocm_etext)) { +#ifdef TRAP_DEBUG_STACK_TRACE + printk(KERN_EMERG "not a text address - " + "address: %08x, stext: %08x, etext: %08x\n" + "ocm_stext: %08x, ocm_etext: %08x\n", + (unsigned int)address, + (unsigned int)stext, + (unsigned int)etext, + (unsigned int)ocm_stext, + (unsigned int)ocm_etext); +#endif + continue; + + } + + /* + * If the address is not on an aligned boundary it can not be a + * return address. + */ + if (address & 0x3) { + continue; + } + + /* + * Read the probable instruction. + */ + instruction = *(unsigned int *)address; + + /* + * Is this a call instruction? + */ + if ((instruction & 0xF8000000) == (u32_t)(0x1B << 27)) { +#ifdef TRAP_DEBUG_STACK_TRACE + printk(KERN_EMERG "call inst. result: %x, " + "test: %x\n", (unsigned int)address, + (unsigned int)instruction); +#endif + *trace = sp; + result = address; + break; + } + + /* + * Is this a calli instruction? + */ + if ((instruction & 0xF8000000) == (u32_t)(0x1E << 27)) { +#ifdef TRAP_DEBUG_STACK_TRACE + printk(KERN_EMERG "calli inst. result: %x, " + "test: %x\n", (unsigned int)address, + (unsigned int)instruction); +#endif + *trace = sp; + result = address; + break; + } + } + + /* + * Restore the current thread to be monitored for traps. + */ + if (thread_trap_en) { + asm volatile( + " thread_get_self_mask d15 \n\t" + " or.4 MT_TRAP_EN, MT_TRAP_EN, d15 \n\t" + : + : + : "d15", "cc" + ); + } + return result; +} + +#ifdef CONFIG_STACKTRACE +/* + * stacktrace_save_entries() + * Save stack back trace information into the provided trace structure. + */ +void stacktrace_save_entries(struct task_struct *tsk, + struct stack_trace *trace, + unsigned long sp) +{ + unsigned long code_start = (unsigned long)&_stext; + unsigned long code_end = (unsigned long)&_etext; + unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin; + unsigned long ocm_code_end = (unsigned long)&__data_begin; + unsigned long stack_end = (unsigned long)(tsk->stack + THREAD_SIZE - 8); + unsigned long stack = (unsigned long)sp; + unsigned int idx = 0; + unsigned long *handle; + int skip = trace->skip; + + handle = (unsigned long *)stack; + while (idx < trace->max_entries) { + if (skip) { + skip--; + continue; + } + trace->entries[idx] = stacktrace_iterate(&handle, + code_start, code_end, + ocm_code_start, ocm_code_end, + (unsigned long)stack, stack_end); + if (trace->entries[idx] == 0) { + break; + } + idx++; + } +} + +/* + * save_stack_trace() + * Save the specified amount of the kernel stack trace information + * for the current task. + */ +void save_stack_trace(struct stack_trace *trace) +{ + unsigned long sp = 0; + asm volatile ( + " move.4 %0, SP \n\t" + : "=r" (sp) + ); + stacktrace_save_entries(current, trace, sp); +} +EXPORT_SYMBOL_GPL(save_stack_trace); + +/* + * save_stack_trace_tsk() + * Save the specified amount of the kernel stack trace information + * for the specified task. + * + * Note: We assume the specified task is not currently running. + */ +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + stacktrace_save_entries(tsk, trace, tsk->thread.sp); +} +EXPORT_SYMBOL_GPL(save_stack_trace_tsk); +#endif /* CONFIG_STACKTRACE */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/sys_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/sys_ubicom32.c new file mode 100644 index 000000000..b06f3f396 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/sys_ubicom32.c @@ -0,0 +1,237 @@ +/* + * arch/ubicom32/kernel/sys_ubicom32.c + * Ubicom32 architecture system call support implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/ubicom32 + * platform. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* common code for old and new mmaps */ +static inline long do_mmap2( + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file *file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to + * handle more than 4 system call parameters, so these system calls + * used a memory block for parameter passing.. + */ + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +asmlinkage int old_mmap(struct mmap_arg_struct *arg) +{ + struct mmap_arg_struct a; + int error = -EFAULT; + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + + error = -EINVAL; + if (a.offset & ~PAGE_MASK) + goto out; + + a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, + a.offset >> PAGE_SHIFT); +out: + return error; +} + +struct sel_arg_struct { + unsigned long n; + fd_set *inp, *outp, *exp; + struct timeval *tvp; +}; + +asmlinkage int old_select(struct sel_arg_struct *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + /* sys_select() does the appropriate kernel locking */ + return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc(uint call, int first, int second, + int third, void *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + return sys_semop(first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget(first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl(first, second, third, fourth); + } + default: + return -EINVAL; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + return sys_msgsnd(first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + if (copy_from_user(&tmp, + (struct ipc_kludge *)ptr, + sizeof(tmp))) + return -EFAULT; + return sys_msgrcv(first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv(first, + (struct msgbuf *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget((key_t) first, second); + case MSGCTL: + return sys_msgctl(first, second, + (struct msqid_ds *) ptr); + default: + return -EINVAL; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = do_shmat(first, ptr, second, &raddr); + if (ret) + return ret; + return put_user(raddr, (ulong __user *) third); + } + } + case SHMDT: + return sys_shmdt(ptr); + case SHMGET: + return sys_shmget(first, second, third); + case SHMCTL: + return sys_shmctl(first, second, ptr); + default: + return -ENOSYS; + } + + return -EINVAL; +} + +/* sys_cacheflush -- flush (part of) the processor cache. */ +asmlinkage int +sys_cacheflush(unsigned long addr, int scope, int cache, unsigned long len) +{ + flush_cache_all(); + return 0; +} + +asmlinkage int sys_getpagesize(void) +{ + return PAGE_SIZE; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/syscalltable.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/syscalltable.S new file mode 100644 index 000000000..8921fb83d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/syscalltable.S @@ -0,0 +1,376 @@ +/* + * arch/ubicom32/kernel/syscalltable.S + * + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +/* + * + * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998 D. Jeff Dionne , Kenneth Albanowski , + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include + +.text +ALIGN + .global sys_call_table +sys_call_table: + .long sys_ni_syscall /* 0 - old "setup()" system call*/ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long execve_intercept + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_chown16 + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid16 + .long sys_getuid16 + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid16 + .long sys_getgid16 + .long sys_signal + .long sys_geteuid16 + .long sys_getegid16 /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid16 /* 70 */ + .long sys_setregid16 + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_old_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups16 /* 80 */ + .long sys_setgroups16 + .long old_select + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_ni_syscall /* _sys_swapon */ + .long sys_reboot + .long sys_old_readdir + .long old_mmap /* 90 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown16 /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ni_syscall /* ioperm for i386 */ + .long sys_socketcall + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_ni_syscall + .long sys_ni_syscall /* iopl for i386 */ /* 110 */ + .long sys_vhangup + .long sys_ni_syscall /* obsolete idle() syscall */ + .long sys_ni_syscall /* vm86old for i386 */ + .long sys_wait4 + .long sys_ni_syscall /* 115 */ /* _sys_swapoff */ + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn + .long clone_intercept /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_cacheflush /* modify_ldt for i386 */ + .long sys_adjtimex + .long sys_ni_syscall /* 125 */ /* _sys_mprotect */ + .long sys_sigprocmask + .long sys_ni_syscall /* old "creat_module" */ + .long sys_init_module + .long sys_delete_module + .long sys_ni_syscall /* 130: old "get_kernel_syms" */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* for afs_syscall */ + .long sys_setfsuid16 + .long sys_setfsgid16 + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_ni_syscall /* _sys_msync */ + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_ni_syscall /* 150 */ /* _sys_mlock */ + .long sys_ni_syscall /* _sys_munlock */ + .long sys_ni_syscall /* _sys_mlockall */ + .long sys_ni_syscall /* _sys_munlockall */ + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_ni_syscall /* _sys_mremap */ + .long sys_setresuid16 + .long sys_getresuid16 /* 165 */ + .long sys_getpagesize /* _sys_getpagesize */ + .long sys_ni_syscall /* old "query_module" */ + .long sys_poll + .long sys_ni_syscall /* _sys_nfsservctl */ + .long sys_setresgid16 /* 170 */ + .long sys_getresgid16 + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_lchown16 + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long vfork_intercept /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_chown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_lchown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_ni_syscall + .long sys_ni_syscall + .long sys_getdents64 /* 220 */ + .long sys_gettid + .long sys_tkill + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr /* 225 */ + .long sys_getxattr + .long sys_lgetxattr + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr /* 230 */ + .long sys_flistxattr + .long sys_removexattr + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_futex /* 235 */ + .long sys_sendfile64 + .long sys_ni_syscall /* _sys_mincore */ + .long sys_ni_syscall /* _sys_madvise */ + .long sys_fcntl64 + .long sys_readahead /* 240 */ + .long sys_io_setup + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel /* 245 */ + .long sys_fadvise64 + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 250 */ + .long sys_epoll_wait + .long sys_ni_syscall /* _sys_remap_file_pages */ + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 255 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 260 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + .long sys_tgkill /* 265 */ + .long sys_utimes + .long sys_fadvise64_64 + .long sys_mbind + .long sys_get_mempolicy + .long sys_set_mempolicy /* 270 */ + .long sys_mq_open + .long sys_mq_unlink + .long sys_mq_timedsend + .long sys_mq_timedreceive + .long sys_mq_notify /* 275 */ + .long sys_mq_getsetattr + .long sys_waitid + .long sys_ni_syscall /* for _sys_vserver */ + .long sys_add_key + .long sys_request_key /* 280 */ + .long sys_keyctl + .long sys_ioprio_set + .long sys_ioprio_get + .long sys_inotify_init + .long sys_inotify_add_watch /* 285 */ + .long sys_inotify_rm_watch + .long sys_migrate_pages + .long sys_openat + .long sys_mkdirat + .long sys_mknodat /* 290 */ + .long sys_fchownat + .long sys_futimesat + .long sys_fstatat64 + .long sys_unlinkat + .long sys_renameat /* 295 */ + .long sys_linkat + .long sys_symlinkat + .long sys_readlinkat + .long sys_fchmodat + .long sys_faccessat /* 300 */ + .long sys_ni_syscall /* Reserved for pselect6 */ + .long sys_ni_syscall /* Reserved for ppoll */ + .long sys_unshare + .long sys_set_robust_list + .long sys_get_robust_list /* 305 */ + .long sys_splice + .long sys_sync_file_range + .long sys_tee + .long sys_vmsplice + .long sys_move_pages /* 310 */ + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_kexec_load + .long sys_getcpu + .long sys_epoll_pwait /* 315 */ + .long sys_utimensat + .long sys_signalfd + .long sys_timerfd_create + .long sys_eventfd + .long sys_fallocate /* 320 */ + .long sys_timerfd_settime + .long sys_timerfd_gettime + .long sys_ni_syscall /* sys_signalfd4 */ + .long sys_ni_syscall /* sys_eventfd2 */ + .long sys_ni_syscall /* sys_epoll_create1 */ + /* 325 */ + .long sys_ni_syscall /* sys_dup3 */ + .long sys_ni_syscall /* sys_pipe2 */ + .long sys_ni_syscall /* sys_inotify_init1 */ + .rept NR_syscalls-(.-sys_call_table)/4 + .long sys_ni_syscall + .endr diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/thread.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/thread.c new file mode 100644 index 000000000..aaa5fbea4 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/thread.c @@ -0,0 +1,228 @@ +/* + * arch/ubicom32/kernel/thread.c + * Ubicom32 architecture hardware thread support. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * TODO: At some point change the name here to be thread_ksp + */ +unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX]; + +static unsigned int thread_mask = -1; +static unsigned int thread_mainline_mask; + +/* + * thread_entry() + * Returning from the called function will disable the thread. + * + * This could be a naked call to allow for hwthreads that do not have stacks. + * However, with -O0, the code still writes to thex stack, and this was + * corrupting memory just after the callers stack. + */ +static void thread_entry(void *arg, thread_exec_fn_t exec) +{ + /* + * Call thread function + */ + exec(arg); + + /* + * Complete => Disable self + */ + thread_disable(thread_get_self()); +} + +/* + * thread_start() + * Start the specified function on the specified hardware thread. + */ +thread_t thread_start(thread_t thread, + thread_exec_fn_t exec, + void *arg, + unsigned int *sp_high, + thread_type_t type) +{ + /* + * Sanity check + */ + unsigned int enabled, mask, csr; + asm volatile ( + "move.4 %0, MT_EN\n\t" + : "=m" (enabled) + ); + + mask = 1 << thread; + if (enabled & mask) { + printk(KERN_WARNING "request to enable a previously enabled thread\n"); + return (thread_t)-1; + } + + /* + * Update thread state + */ + csr = (thread << 15) | (1 << 14); + asm volatile ( + "setcsr %0 \n\t" + "setcsr_flush 0 \n\t" + + "move.4 A0, #0 \n\t" + "move.4 A1, #0 \n\t" + "move.4 A2, #0 \n\t" + "move.4 A3, #0 \n\t" + "move.4 A4, #0 \n\t" + "move.4 A5, #0 \n\t" + "move.4 A6, #0 \n\t" + "move.4 SP, %4 \n\t" /* A7 is SP */ + + "move.4 D0, %3 \n\t" + "move.4 D1, %2 \n\t" + "move.4 D2, #0 \n\t" + "move.4 D3, #0 \n\t" + "move.4 D4, #0 \n\t" + "move.4 D5, #0 \n\t" + "move.4 D6, #0 \n\t" + "move.4 D7, #0 \n\t" + "move.4 D8, #0 \n\t" + "move.4 D9, #0 \n\t" + "move.4 D10, #0 \n\t" + "move.4 D11, #0 \n\t" + "move.4 D12, #0 \n\t" + "move.4 D13, #0 \n\t" + "move.4 D14, #0 \n\t" + "move.4 D15, #0 \n\t" + + "move.4 INT_MASK0, #0 \n\t" + "move.4 INT_MASK1, #0 \n\t" + "move.4 PC, %1 \n\t" + "setcsr #0 \n\t" + "setcsr_flush 0 \n\t" + : + : "r" (csr), "r" (thread_entry), "r" (exec), + "r" (arg), "r" (sp_high) + ); + + /* + * Apply HRT state + */ + if (type & THREAD_TYPE_HRT) { + asm volatile ( + "or.4 MT_HRT, MT_HRT, %0\n\t" + : + : "d" (mask) + : "cc" + ); + } else { + asm volatile ( + "and.4 MT_HRT, MT_HRT, %0\n\t" + : + : "d" (~mask) + : "cc" + ); + } + + /* + * Set priority + */ + asm volatile ( + "or.4 MT_HPRI, MT_HPRI, %0\n\t" + : + : "d" (mask) + : "cc" + ); + + /* + * Enable thread + */ + asm volatile ( + "move.4 MT_ACTIVE_SET, %0 \n\t" + : + : "d" (mask) + ); + thread_enable_mask(mask); + return thread; +} + +/* + * thread_get_mainline() + * Return a mask of those threads that are Linux mainline threads. + */ +unsigned int thread_get_mainline(void) +{ + return thread_mainline_mask; +} + +/* + * thread_set_mainline() + * Indicate that the specified thread is a Linux mainline thread. + */ +void thread_set_mainline(thread_t tid) +{ + thread_mainline_mask |= (1 << tid); +} + +/* + * thread_alloc() + * Allocate an unused hardware thread. + */ +thread_t thread_alloc(void) +{ + thread_t tid; + + /* + * If this is the first time we are here get the list of unused + * threads from the processor device tree node. + */ + if (thread_mask == -1) { + thread_mask = processor_threads(); + } + + if (!thread_mask) { + return (thread_t)-1; + } + + tid = ffs(thread_mask); + if (tid != 0) { + tid--; + thread_mask &= ~(1 << tid); + return tid; + } + + return (thread_t)-1; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/time.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/time.c new file mode 100644 index 000000000..4a99284bd --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/time.c @@ -0,0 +1,212 @@ +/* + * arch/ubicom32/kernel/time.c + * Initialize the timer list and start the appropriate timers. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include + +/* + * A bitmap of the timers on the processor indicates + * that the timer is free or in-use. + */ +static unsigned int timers; + +/* + * timer_set() + * Init the specified compare register to go off cycles from now. + */ +void timer_set(int timervector, unsigned int cycles) +{ + int idx = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector); + UBICOM32_IO_TIMER->syscom[idx] = + UBICOM32_IO_TIMER->sysval + cycles; + ldsr_enable_vector(timervector); +} + +/* + * timer_reset() + * Set/reset the timer to go off again. + * + * Because sysval is a continuous timer, this function is able + * to ensure that we do not have clock sku by using the previous + * value in syscom to set the next value for syscom. + * + * Returns the number of ticks that transpired since the last event. + */ +int timer_reset(int timervector, unsigned int cycles) +{ + /* + * Reset the timer in the LDSR thread to go off appropriately. + * + * Use the previous value of the timer to calculate the new stop + * time. This allows us to account for it taking an + * indeterminate amount of time to get here. + */ + const int timer_index = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector); + unsigned int prev = UBICOM32_IO_TIMER->syscom[timer_index]; + unsigned int next = prev + cycles; + int scratchpad3; + int diff; + int ticks = 1; + + /* + * If the difference is negative, we have missed at least one + * timer tick. + * + * TODO: Decide if we want to "ignore" time (as done below) or + * if we want to process time (unevenly) by calling timer_tick() + * lost_ticks times. + */ + while (1) { + /* + * Set our future time first. + */ + UBICOM32_IO_TIMER->syscom[timer_index] = next; + + /* + * Then check if we are really set time in the futrue. + */ + diff = (int)next - (int)UBICOM32_IO_TIMER->sysval; + if (diff >= 0) { + break; + } + + /* + * Oops, we are too slow. Playing catch up. + * + * If the debugger is connected the there is a good + * chance that we lost time because we were in a + * break-point, so in this case we do not print out + * diagnostics. + */ + asm volatile ("move.4 %0, scratchpad3" + : "=r" (scratchpad3)); + if ((scratchpad3 & 0x1) == 0) { + /* + * No debugger attached, print to the console + */ + printk(KERN_EMERG "diff: %d, timer has lost %u " + "ticks [rounded up]\n", + -diff, + (unsigned int)((-diff + cycles - 1) / cycles)); + } + + do { + next += cycles; + diff = (int)next - (int)UBICOM32_IO_TIMER->sysval; + ticks++; + } while (diff < 0); + } + return ticks; +} + +/* + * sched_clock() + * Returns current time in nano-second units. + * + * Notes: + * 1) This is an override for the weak alias in + * kernel/sched_clock.c. + * 2) Do not use xtime_lock as this function is + * sometimes called with xtime_lock held. + * 3) We use a retry algorithm to ensure that + * we get a consistent value. + * 4) sched_clock must be overwritten if IRQ tracing + * is enabled because the default implementation uses + * the xtime_lock sequence while holding xtime_lock. + */ +unsigned long long sched_clock(void) +{ + unsigned long long my_jiffies; + unsigned long jiffies_top; + unsigned long jiffies_bottom; + + do { + jiffies_top = jiffies_64 >> 32; + jiffies_bottom = jiffies_64 & 0xffffffff; + } while (unlikely(jiffies_top != (unsigned long)(jiffies_64 >> 32))); + + my_jiffies = ((unsigned long long)jiffies_top << 32) | (jiffies_bottom); + return (my_jiffies - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ); +} + +/* + * timer_free() + * Free a hardware timer. + */ +void timer_free(int interrupt) +{ + unsigned int bit = interrupt - TIMER_INT(0); + + /* + * The timer had not been allocated. + */ + BUG_ON(timers & (1 << bit)); + timers |= (1 << bit); +} + +/* + * timer_alloc() + * Allocate a hardware timer. + */ +int timer_alloc(void) +{ + unsigned int bit = find_first_bit((unsigned long *)&timers, 32); + if (!bit) { + printk(KERN_WARNING "no more free timers\n"); + return -1; + } + + timers &= ~(1 << bit); + return bit + TIMER_INT(0); +} + +/* + * time_init() + * Time init function. + */ +void time_init(void) +{ + /* + * Find the processor node and determine what timers are + * available for us. + */ + timers = processor_timers(); + if (timers == 0) { + printk(KERN_WARNING "no timers are available for Linux\n"); + return; + } + +#ifdef CONFIG_GENERIC_CLOCKEVENTS + timer_device_init(); +#else + timer_tick_init(); +#endif +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_broadcast.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_broadcast.c new file mode 100644 index 000000000..8f0cdc4d5 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_broadcast.c @@ -0,0 +1,102 @@ +/* + * arch/ubicom32/kernel/timer_broadcast.c + * Implements a dummy clock event for each cpu. + * + * Copyright (C) 2008 Paul Mundt + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * arch/arm + * arch/sh + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); + +/* + * The broadcast trick only works when the timer will be used in a periodic mode. + * If the user has configured either NO_HZ or HIGH_RES_TIMERS they must have + * a per cpu timer. + */ +#if defined(CONFIG_NO_HZ) || defined(CONFIG_HIGH_RES_TIMERS) +#error "Tickless and High Resolution Timers require per-CPU local timers: CONFIG_LOCAL_TIMERS" +#endif + +/* + * local_timer_interrupt() + * Used on SMP for local timer interrupt sent via an IPI. + */ +void local_timer_interrupt(void) +{ + struct clock_event_device *dev = &__get_cpu_var(local_clockevent); + + dev->event_handler(dev); +} + +/* + * dummy_timer_set_next_event() + * Cause the timer to go off "cycles" from now. + */ +static int dummy_timer_set_next_event(unsigned long cycles, struct clock_event_device *dev) +{ + return 0; +} + +/* + * dummy_timer_set_mode() + * Do Nothing. + */ +static void dummy_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ +} + +/* + * local_timer_setup() + * Adds a clock event for the specified cpu. + */ +int __cpuinit local_timer_setup(unsigned int cpu) +{ + struct clock_event_device *dev = &per_cpu(local_clockevent, cpu); + + dev->name = "timer-dummy"; + dev->features = CLOCK_EVT_FEAT_DUMMY; + dev->rating = 200; + dev->mult = 1; + dev->set_mode = dummy_timer_set_mode; + dev->set_next_event = dummy_timer_set_next_event; + dev->broadcast = smp_timer_broadcast; + dev->cpumask = cpumask_of_cpu(cpu); + dev->irq = -1; + printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name); + + clockevents_register_device(dev); + return 0; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_device.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_device.c new file mode 100644 index 000000000..1943cbb9e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_device.c @@ -0,0 +1,301 @@ +/* + * arch/ubicom32/kernel/timer_device.c + * Implements a Ubicom32 clock device and event devices. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_SMP) +#include +#endif + +#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) +#define MAX_TIMERS (2 + CONFIG_TIMER_EXTRA_ALLOC) +#else +#define MAX_TIMERS (NR_CPUS + CONFIG_TIMER_EXTRA_ALLOC) +#endif + +#if (MAX_TIMERS > 10) +#error "Ubicom32 only has 10 timers" +#endif + +static unsigned int frequency; +static struct clock_event_device timer_device_devs[MAX_TIMERS]; +static struct irqaction timer_device_irqs[MAX_TIMERS]; +static int timer_device_next_timer = 0; + +DEFINE_SPINLOCK(timer_device_lock); + +/* + * timer_device_set_next_event() + * Cause the timer to go off "cycles" from now. + */ +static int timer_device_set_next_event(unsigned long cycles, struct clock_event_device *dev) +{ + timer_set(dev->irq, cycles); + return 0; +} + +/* + * timer_device_set_mode() + * Handle the mode switch for a clock event device. + */ +static void timer_device_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) +{ + switch (mode) { + case CLOCK_EVT_MODE_SHUTDOWN: + /* + * Make sure the vector is disabled + * until the next event is set. + */ + printk(KERN_NOTICE "timer[%d]: shutdown\n", dev->irq); + ldsr_disable_vector(dev->irq); + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* + * Make sure the vector is disabled + * until the next event is set. + */ + printk(KERN_NOTICE "timer[%d]: oneshot\n", dev->irq); + ldsr_disable_vector(dev->irq); + break; + + case CLOCK_EVT_MODE_PERIODIC: + /* + * The periodic request is 1 per jiffies + */ + printk(KERN_NOTICE "timer[%d]: periodic: %d cycles\n", + dev->irq, frequency / CONFIG_HZ); + timer_set(dev->irq, frequency / CONFIG_HZ); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_RESUME: + printk(KERN_WARNING "timer[%d]: unimplemented mode: %d\n", + dev->irq, mode); + break; + }; +} + +/* + * timer_device_event() + * Call the device's event handler. + * + * The pointer is initialized by the generic Linux code + * to the function to be called. + */ +static irqreturn_t timer_device_event(int irq, void *dev_id) +{ + struct clock_event_device *dev = (struct clock_event_device *)dev_id; + + if (dev->mode == CLOCK_EVT_MODE_PERIODIC) { + /* + * The periodic request is 1 per jiffies + */ + timer_reset(dev->irq, frequency / CONFIG_HZ); + } else { + /* + * The timer will go off again at the rollover + * point. We must disable the IRQ to prevent + * getting a spurious interrupt. + */ + ldsr_disable_vector(dev->irq); + } + + if (!dev->event_handler) { + printk(KERN_CRIT "no registered event handler\n"); + return IRQ_HANDLED; + } + + dev->event_handler(dev); + return IRQ_HANDLED; +} + +/* + * timer_device_clockbase_read() + * Provide a primary clocksource around the sysval timer. + */ +static cycle_t timer_device_clockbase_read(void) +{ + return (cycle_t)UBICOM32_IO_TIMER->sysval; +} + +/* + * Primary Clock Source Description + * + * We use 24 for the shift factor because we want + * to ensure there are less than 2^24 clocks + * in a jiffie of 10 ms. + */ +static struct clocksource timer_device_clockbase = { + .name = "sysval", + .rating = 400, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .mask = CLOCKSOURCE_MASK(32), + .shift = 24, + .mult = 0, + .read = timer_device_clockbase_read, +}; + +/* + * timer_device_alloc_event() + * Allocate a timer device event. + */ +static int timer_device_alloc_event(const char *name, int cpuid, const struct cpumask *cpumask) +{ + struct clock_event_device *dev; + struct irqaction *action; + + /* + * Are we out of configured timers? + */ + spin_lock(&timer_device_lock); + if (timer_device_next_timer >= MAX_TIMERS) { + spin_unlock(&timer_device_lock); + printk(KERN_WARNING "out of timer event entries\n"); + return -1; + } + dev = &timer_device_devs[timer_device_next_timer]; + action = &timer_device_irqs[timer_device_next_timer]; + timer_device_next_timer++; + spin_unlock(&timer_device_lock); + + /* + * Now allocate a timer to ourselves. + */ + dev->irq = timer_alloc(); + if (dev->irq == -1) { + spin_lock(&timer_device_lock); + timer_device_next_timer--; + spin_unlock(&timer_device_lock); + printk(KERN_WARNING "out of hardware timers\n"); + return -1; + } + + /* + * Init the IRQ action structure. Make sure + * this in place before you register the clock + * event device. + */ + action->name = name; + action->flags = IRQF_DISABLED | IRQF_TIMER; + action->handler = timer_device_event; + //cpumask_copy(&action->mask, mask); + action->dev_id = dev; + setup_irq(dev->irq, action); + irq_set_affinity(dev->irq, cpumask); + ldsr_disable_vector(dev->irq); + + /* + * init clock dev structure. + * + * The min_delta_ns is chosen to ensure that setting next + * event will never be requested with too small of value. + */ + dev->name = name; + dev->rating = timer_device_clockbase.rating; + dev->shift = timer_device_clockbase.shift; + dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + dev->set_mode = timer_device_set_mode; + dev->set_next_event = timer_device_set_next_event; + dev->mult = div_sc(frequency, NSEC_PER_SEC, dev->shift); + dev->max_delta_ns = clockevent_delta2ns(0xffffffff, dev); + dev->min_delta_ns = clockevent_delta2ns(100, dev); + //dev->cpumask = mask; + printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name); + + /* + * Now register the device. + */ + clockevents_register_device(dev); + return dev->irq; +} + +#if defined(CONFIG_LOCAL_TIMERS) +/* + * local_timer_setup() + * Allocation function for creating a per cpu local timer. + */ +int __cpuinit local_timer_setup(unsigned int cpu) +{ + return timer_device_alloc_event("timer-cpu", cpu); +} +#endif + +/* + * timer_device_init() + * Create and init a generic clock driver for Ubicom32. + */ +void timer_device_init(void) +{ + int i; + + /* + * Get the frequency from the processor device tree node or use + * the default if not available. We will store this as the frequency + * of the timer to avoid future calculations. + */ + frequency = processor_frequency(); + if (frequency == 0) { + frequency = CLOCK_TICK_RATE; + } + + /* + * Setup the primary clock source around sysval. Linux does not + * supply a Mhz multiplier so convert down to khz. + */ + timer_device_clockbase.mult = + clocksource_khz2mult(frequency / 1000, + timer_device_clockbase.shift); + if (clocksource_register(&timer_device_clockbase)) { + printk(KERN_ERR "timer: clocksource failed to register\n"); + return; + } + + /* + * Always allocate a primary timer. + */ + timer_device_alloc_event("timer-primary", -1, cpu_all_mask); + +#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) + /* + * If BROADCAST is selected we need to add a broadcast timer. + */ + timer_device_alloc_event("timer-broadcast", -1, cpu_all_mask); +#endif + + /* + * Allocate extra timers that are requested. + */ + for (i = 0; i < CONFIG_TIMER_EXTRA_ALLOC; i++) { + timer_device_alloc_event("timer-extra", -1, cpu_all_mask); + } +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_tick.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_tick.c new file mode 100644 index 000000000..7a2ad4949 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_tick.c @@ -0,0 +1,109 @@ +/* + * arch/ubicom32/kernel/timer_tick.c + * Impelemets a perodic timer. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include + +#include +#include +#if defined(CONFIG_SMP) +#include +#endif + +static unsigned int timervector; +static unsigned int frequency; + +/* + * timer_tick() + * Kernel system timer support. Needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick. + */ +static irqreturn_t timer_tick(int irq, void *dummy) +{ + int ticks; + + BUG_ON(!irqs_disabled()); + ticks = timer_reset(timervector, frequency); + + write_seqlock(&xtime_lock); + do_timer(ticks); + write_sequnlock(&xtime_lock); + + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); + +#if defined(CONFIG_SMP) + smp_send_timer_all(); +#endif + return(IRQ_HANDLED); +} + +/* + * Data used by setup_irq for the timer. + */ +static struct irqaction timer_irq = { + .name = "timer", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = timer_tick, +}; + +/* + * timer_tick_init() + * Implements a periodic timer + * + * This implementation directly calls the timer_tick() and move + * the Linux kernel forward. This is used when the user has not + * selected GENERIC_CLOCKEVENTS. + */ +void timer_tick_init(void) +{ + /* + * Now allocate a timer to ourselves. + */ + timervector = timer_alloc(); + if (timervector == -1) { + printk(KERN_WARNING "where did the timer go?\n"); + return; + } + + setup_irq(timervector, &timer_irq); + + /* + * Get the frequency from the processor device tree node or use + * the default if not available. We will store this as the frequency + * of the timer to avoid future calculations. + */ + frequency = processor_frequency(); + if (frequency == 0) { + frequency = CLOCK_TICK_RATE; + } + frequency /= CONFIG_HZ; + + printk(KERN_NOTICE "timer will interrupt every: %d cycles\n", frequency); + timer_set(timervector, frequency); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/topology.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/topology.c new file mode 100644 index 000000000..0676a1658 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/topology.c @@ -0,0 +1,47 @@ +/* + * arch/ubicom32/kernel/topology.c + * Ubicom32 architecture sysfs topology information. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include + +static struct cpu cpu_devices[NR_CPUS] __read_mostly; + +static int __init topology_init(void) +{ + int num; + + for_each_present_cpu(num) { + cpu_devices[num].hotpluggable = 0; + register_cpu(&cpu_devices[num], num); + } + return 0; +} + +subsys_initcall(topology_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c new file mode 100644 index 000000000..8cb22e25e --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c @@ -0,0 +1,514 @@ +/* + * arch/ubicom32/kernel/traps.c + * Ubicom32 architecture trap handling support. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +/* + * Sets up all exception vectors + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRAP_MAX_STACK_DEPTH 20 + +/* + * These symbols are filled in by the linker. + */ +extern unsigned long _stext; +extern unsigned long _etext; + +extern unsigned long __ocm_text_run_begin; +extern unsigned long __data_begin; + +extern void show_vmas(struct task_struct *task); + +const char *trap_cause_strings[] = { + /*0*/ "inst address decode error", + /*1*/ "inst sync error", + /*2*/ "inst illegal", + /*3*/ "src1 address decode error", + /*4*/ "dst address decode error", + /*5*/ "src1 alignment error", + /*6*/ "dst alignment error", + /*7*/ "src1 sync error", + /*8*/ "dst sync error", + /*9*/ "DCAPT error", + /*10*/ "inst range error", + /*11*/ "src1 range error", + /*12*/ "dst range error", +}; + +/* + * The device tree trap node definition. + */ +struct trapnode { + struct devtree_node dn; + unsigned int intthread; +}; + +static struct trapnode *tn;; + +/* + * trap_interrupt_handler() + * Software Interrupt to ensure that a trap is serviced. + */ +static irqreturn_t trap_interrupt_handler(int irq, void *dummy) +{ + /* Do Nothing */ + return IRQ_HANDLED; +} + +/* + * Data used by setup_irq for the timer. + */ +static struct irqaction trap_irq = { + .name = "trap", + .flags = IRQF_DISABLED, + .handler = trap_interrupt_handler, +}; + +/* + * trap_cause_to_str() + * Convert a trap_cause into a series of printk + */ +static void trap_cause_to_str(long status) +{ + int bit; + + if ((status & ((1 << TRAP_CAUSE_TOTAL) - 1)) == 0) { + printk(KERN_NOTICE "decode: UNKNOWN CAUSES\n"); + return; + } + + for (bit = 0; bit < TRAP_CAUSE_TOTAL; bit++) { + if (status & (1 << bit)) { + printk(KERN_NOTICE "\tdecode: %08x %s\n", + 1 << bit, trap_cause_strings[bit]); + } + } +} + +/* + * trap_print_information() + * Print the cause of the trap and additional info. + */ +static void trap_print_information(const char *str, struct pt_regs *regs) +{ + printk(KERN_WARNING "\n"); + + if (current) { + printk(KERN_WARNING "Process %s (pid: %d)\n", + current->comm, current->pid); + } + + if (current && current->mm) { + printk(KERN_NOTICE "text = 0x%p-0x%p data = 0x%p-0x%p\n" + KERN_NOTICE "bss = 0x%p-0x%p user-stack = 0x%p\n" + KERN_NOTICE "\n", + (void *)current->mm->start_code, + (void *)current->mm->end_code, + (void *)current->mm->start_data, + (void *)current->mm->end_data, + (void *)current->mm->end_data, + (void *)current->mm->brk, + (void *)current->mm->start_stack); + } + + printk(KERN_WARNING "%s: Causes: 0x%08x\n", str, + (unsigned int)regs->trap_cause); + trap_cause_to_str(regs->trap_cause); + show_regs(regs); + show_stack(NULL, (unsigned long *)regs->an[7]); + printk(KERN_NOTICE "--- End Trap --- \n"); +} + +/* + * dump_stack() + * Dump the stack of the current task. + */ +void dump_stack(void) +{ + show_stack(NULL, NULL); +} +EXPORT_SYMBOL(dump_stack); + +/* + * show_stack() + * Print out information from the current stack. + */ +void show_stack(struct task_struct *task, unsigned long *sp) +{ + /* + * Allocate just enough entries on the stack. + */ + unsigned int calls[TRAP_MAX_STACK_DEPTH]; + unsigned long code_start; + unsigned long code_end; + unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin; + unsigned long ocm_code_end = (unsigned long)&__data_begin; + unsigned long stack_end = (unsigned long)(current->stack + THREAD_SIZE - 8); + unsigned long stack = (unsigned long)sp; + int kernel_stack = 1; + + processor_dram(&code_start, &code_end); + + /* + * Which task are we talking about. + */ + if (!task) { + task = current; + } + + /* + * Find the stack for the task if one was not specified. Otherwise + * use the specified stack. + */ + if (!stack) { + if (task != current) { + stack = task->thread.sp; + stack_end = (unsigned long)task->stack + THREAD_SIZE - 8; + } else { + asm volatile ( + "move.4 %0, SP \n\t" + : "=r" (stack) + ); + } + } + + printk(KERN_NOTICE "Starting backtrace: PID %d '%s'\n", + task->pid, task->comm); + + /* + * We do 2 passes the first pass is Kernel stack is the second + * User stack. + */ + while (kernel_stack) { + unsigned long *handle; + unsigned int i, idx = 0; + struct pt_regs *pt = task_pt_regs(task); + + /* + * If the task is in user mode, reset the start + * and end values for text. + */ + if (__user_mode(stack)) { + if (!(task->personality & FDPIC_FUNCPTRS)) { + printk(KERN_NOTICE " User Stack:\n"); + code_start = task->mm->start_code; + code_end = task->mm->end_code; + } else { + printk(KERN_NOTICE " User Stack (fdpic):\n"); + show_vmas(task); + } + stack_end = task->mm->start_stack; + ocm_code_end = ocm_code_start = 0; + kernel_stack = 0; + } else { + printk(KERN_NOTICE " Kernel Stack:\n"); + } + + /* + * Collect the stack back trace information. + */ + printk(" code[0x%lx-0x%lx]", code_start, code_end); + if (ocm_code_start) { + printk(" ocm_code[0x%lx-0x%lx]", + ocm_code_start, ocm_code_end); + } + printk("\n stack[0x%lx-0x%lx]\n", stack, stack_end); + + handle = (unsigned long*)stack; + while (idx < TRAP_MAX_STACK_DEPTH) { + calls[idx] = stacktrace_iterate(&handle, + code_start, code_end, + ocm_code_start, ocm_code_end, + (unsigned long)stack, stack_end); + if (calls[idx] == 0) { + break; + } + idx++; + } + + /* + * Now print out the data. + */ + printk(KERN_NOTICE " CALL && CALLI on stack:"); + for (i = 0; i < idx; i++) { + printk("%s0x%x, ", (i & 0x3) == 0 ? "\n " : "", + calls[i]); + } + printk(idx == TRAP_MAX_STACK_DEPTH ? "...\n" : "\n"); + + /* + * If we are doing user stack we are done + */ + if (!kernel_stack) { + break; + } + + /* + * Does this kernel stack have a mm (i.e. is it user) + */ + if (!task->mm) { + printk("No mm for userspace stack.\n"); + break; + } + /* + * Get the user-mode stack (if any) + */ + stack = pt->an[7]; + printk(KERN_NOTICE "Userspace stack at 0x%lx frame type %d\n", + stack, (int)pt->frame_type); + if (!__user_mode(stack)) { + break; + } + } +} + +/* + * die_if_kernel() + * Determine if we are in kernel mode and if so print stuff out and die. + */ +void die_if_kernel(char *str, struct pt_regs *regs, long trap_cause) +{ + unsigned int s3value; + + if (user_mode(regs)) { + return; + } + + console_verbose(); + trap_print_information(str, regs); + + /* + * If the debugger is attached via the hardware mailbox protocol, + * go into an infinite loop and the debugger will figure things out. + */ + asm volatile ( + "move.4 %0, scratchpad3" + : "=r" (s3value) + ); + if (s3value) { + asm volatile("1: jmpt.t 1b"); + } + + /* + * Set the debug taint value. + */ + add_taint(TAINT_DIE); + do_exit(SIGSEGV); +} + +/* + * trap_handler() + * Handle traps. + * + * Traps are treated as interrupts and registered with the LDSR. When + * the LDSR takes the interrupt, it will determine if a trap has occurred + * and service the trap prior to servicing the interrupt. + * + * This function is directly called by the LDSR. + */ +void trap_handler(int irq, struct pt_regs *regs) +{ + int sig = SIGSEGV; + siginfo_t info; + unsigned int trap_cause = regs->trap_cause; + + BUG_ON(!irqs_disabled()); + + /* + * test if in kernel and die. + */ + die_if_kernel("Kernel Trap", regs, trap_cause); + + /* + * User process problem, setup a signal for this process + */ + if ((trap_cause & (1 << TRAP_CAUSE_DST_RANGE_ERR)) || + (trap_cause & (1 << TRAP_CAUSE_SRC1_RANGE_ERR)) || + (trap_cause & (1 << TRAP_CAUSE_I_RANGE_ERR))) { + sig = SIGSEGV; + info.si_code = SEGV_MAPERR; + } else if ((trap_cause & (1 << TRAP_CAUSE_DST_MISALIGNED)) || + (trap_cause & (1 << TRAP_CAUSE_SRC1_MISALIGNED))) { + sig = SIGBUS; + info.si_code = BUS_ADRALN; + } else if ((trap_cause & (1 << TRAP_CAUSE_DST_DECODE_ERR)) || + (trap_cause & (1 << TRAP_CAUSE_SRC1_DECODE_ERR))) { + sig = SIGILL; + info.si_code = ILL_ILLOPN; + } else if ((trap_cause & (1 << TRAP_CAUSE_ILLEGAL_INST))) { + /* + * Check for software break point and if found signal trap + * not illegal instruction. + */ + unsigned long instruction; + if (between(regs->pc, KERNELSTART, memory_end) && + (regs->pc & 3) == 0 && + get_user(instruction, (unsigned long *)regs->pc) == 0) { + + /* + * This used to be 0xaabbccdd but it turns out + * that is now valid in ubicom32v4 isa so we + * have switched to 0xfabbccdd + */ + if ((instruction == 0xfabbccdd) || + (instruction == 0xaabbccdd)) { + sig = SIGTRAP; + info.si_code = TRAP_BRKPT; + goto send_signal; + } + } + sig = SIGILL; + info.si_code = ILL_ILLOPC; + } else if ((trap_cause & (1 << TRAP_CAUSE_I_DECODE_ERR))) { + sig = SIGILL; + info.si_code = ILL_ILLOPC; + } else if ((trap_cause & (1 << TRAP_CAUSE_DCAPT))) { + sig = SIGTRAP; + info.si_code = TRAP_TRACE; + } + + /* + * Print a trap information block to the console, do not + * print this above the case because we don't want it + * printed for software break points. + */ + trap_print_information("User Trap", regs); + +send_signal: + + force_sig_info(sig, &info, current); + + /* + * Interrupts are disabled, re-enable them now. + */ + if (!irqs_disabled()) { + printk(KERN_EMERG "interrupts enabled on exit, irq=%d, regs=%p", + irq, regs); + BUG(); + } +} + +/* + * trap_init_interrupt() + * We need a 2nd trap handling init that will occur after init_IRQ(). + */ +void __init trap_init_interrupt(void) +{ + int err; + unsigned char tirq; + struct devtree_node *dn = (struct devtree_node *)tn; + + /* + * Now setup the Software IRQ so that if a trap occurs the LDSR + * is started. The irq is there just to "force" the LDSR to run. + */ + if (!tn) { + printk(KERN_WARNING "trap_init_interrupt skipped.\n"); + return; + } + + err = devtree_irq(dn, NULL, &tirq); + if (err) { + printk(KERN_WARNING "error obtaining trap irq value: %d\n", + err); + return; + } + + if (tirq == DEVTREE_IRQ_NONE) { + printk(KERN_WARNING "trap irq not available: %d\n", tirq); + return; + } + + err = setup_irq(tirq, &trap_irq); + if (err) { + printk(KERN_WARNING "trap irq setup failed: %d\n", err); + return; + } + + /* + * Let ultra know which thread is handling the traps and + * what the interrupt to use is. + */ + tn->intthread = ldsr_get_threadid(); + + /* + * Tell the LDSR about our IRQ so that it will unsuspend + * if one occurs while waiting for the per thread lock. + */ + ldsr_set_trap_irq(tirq); +} + +/* + * trap_init() + * init trap handling + * + * Trap handling is done through the ldsr. Every time an interrupt + * occurs, the LDSR looks for threads that are listed in the TRAP + * register and forces a call to the trap handler. + */ +void __init trap_init(void) +{ + /* + * If we do not have a trap node in the device tree, we leave the fault + * handling to the underlying hardware. + */ + tn = (struct trapnode *)devtree_find_node("traps"); + if (!tn) { + printk(KERN_WARNING "traps are not handled by linux\n"); + return; + } +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/uaccess.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/uaccess.c new file mode 100644 index 000000000..2fe5f5f87 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/uaccess.c @@ -0,0 +1,109 @@ +/* + * arch/ubicom32/include/asm/uaccess.c + * User space memory access functions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include + +#include +#include + +extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; + +/* + * __access_ok() + * Check that the address is in the current processes. + * + * NOTE: The kernel uses "pretend" user addresses that wind + * up calling access_ok() so this approach has only marginal + * value because you wind up with lots of false positives. + */ +int __access_ok(unsigned long addr, unsigned long size) +{ + // struct vm_area_struct *vma; + + /* + * Don't do anything if we are not a running system yet. + */ + if (system_state != SYSTEM_RUNNING) { + return 1; + } + + /* + * It appears that Linux will call this function even when we are not + * in the context of a user space application that has a VM address + * space. So we must check that current and mm are valid before + * performing the check. + */ + if ((!current) || (!current->mm)) { + return 1; + } + + /* + * We perform some basic checks on the address to ensure that it + * is at least within the range of DRAM. + */ + if ((addr < (int)&_etext) || (addr > memory_end)) { + printk(KERN_WARNING "pid=%d[%s]: range [%lx - %lx] not in memory area: [%lx - %lx]\n", + current->pid, current->comm, + addr, addr + size, + memory_start, memory_end); + return 0; + } + + /* + * For nommu Linux we can check this by looking at the allowed + * memory map for the process. + * + * TODO: Since the kernel passes addresses in it's own space as though + * they were user address, we can not validate the addresses this way. + */ +#if 0 + if (!down_read_trylock(¤t->mm->mmap_sem)) { + return 1; + } + vma = find_vma(current->mm, addr); + if (!vma) { + up_read(¤t->mm->mmap_sem); + printk(KERN_WARNING "pid=%d[%s]: possible invalid acesss on range: [%lx - %lx]\n", + current->pid, current->comm, addr, addr + size); + return 1; + } + if ((addr + size) > vma->vm_end) { + up_read(¤t->mm->mmap_sem); + printk(KERN_WARNING "pid=%d[%s]: possible invalid length on range: [%lx - %lx]\n", + current->pid, current->comm, addr, addr + size); + return 1; + } + up_read(¤t->mm->mmap_sem); +#endif + return 1; +} + +EXPORT_SYMBOL(__access_ok); diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_context_switch.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_context_switch.S new file mode 100644 index 000000000..08db4c057 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_context_switch.S @@ -0,0 +1,359 @@ +/* + * arch/ubicom32/kernel/ubicom32_context_switch.S + * Implements context switch and return functions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include + +/* + * begin_restore_context() + * Restore most of the context from sp (struct pt_reg *) + * + * This *can* be called without the global atomic lock. (because sp is + * not restored!) Only d15 and a3 are allowed to be used after this + * before calling complete_restore_context + */ +.macro begin_restore_context + move.4 d0, PT_D0(sp) + move.4 d1, PT_D1(sp) + move.4 d2, PT_D2(sp) + move.4 d3, PT_D3(sp) + move.4 d4, PT_D4(sp) + move.4 d5, PT_D5(sp) + move.4 d6, PT_D6(sp) + move.4 d7, PT_D7(sp) + move.4 d8, PT_D8(sp) + move.4 d9, PT_D9(sp) + move.4 d10, PT_D10(sp) + move.4 d11, PT_D11(sp) + move.4 d12, PT_D12(sp) + move.4 d13, PT_D13(sp) + move.4 d14, PT_D14(sp) +;; move.4 d15, PT_D15(sp) + move.4 a0, PT_A0(sp) + move.4 a1, PT_A1(sp) + move.4 a2, PT_A2(sp) +;; move.4 a3, PT_A3(sp) + move.4 a4, PT_A4(sp) + move.4 a5, PT_A5(sp) + move.4 a6, PT_A6(sp) + move.4 acc0_hi, PT_ACC0HI(sp) + move.4 acc0_lo, PT_ACC0LO(sp) + move.4 mac_rc16, PT_MAC_RC16(sp) + move.4 acc1_hi, PT_ACC1HI(sp) + move.4 acc1_lo, PT_ACC1LO(sp) + move.4 source3, PT_SOURCE3(sp) + move.4 int_mask0, PT_INT_MASK0(sp) + move.4 int_mask1, PT_INT_MASK1(sp) +.endm + +/* + * complete_restore_context() + * Completely restore the context from sp (struct pt_reg *) + * + * Note: Recovered PC and CSR are saved on the stack and are to be + * popped off before returning. + */ +.macro complete_restore_context + move.4 a3, sp + move.4 d15, PT_D15(sp) + move.4 sp, PT_SP(a3) ; Recover Stack pointer from save area + move.4 -4(sp)++, PT_PC(a3) ; Recover saved PC and save to stack + move.4 -4(sp)++, PT_CSR(a3) ; Recover saved csr and save to stack + move.4 a3, PT_A3(a3) +.endm + +/* + * old restore_context macro + */ +.macro restore_context + begin_restore_context + complete_restore_context +.endm + +/* + * ldsr_thread_enable_interrupts() + * An assembly version of the enable interrupts function. + * + * The stack is fair game but all registers MUST be preserved. + * + */ +.macro ldsr_thread_enable_interrupts + move.4 -4(sp)++, d3 ; Push d3 + move.4 -4(sp)++, a3 ; Push a3 + + /* + * Read the ROSR and obtain ~(1 << tid) + */ + lsr.4 d3, rosr, #0x2 ; Move the thread portion of ROSR into d3 + lsl.4 d3, #1, d3 ; perform a (1 << tid) + not.4 d3, d3 ; Negate the value of d3 == ~(1 << threadid) + + /* + * Get the value of the ldsr_soft_irq_mask + */ + moveai a3, #%hi(ldsr_soft_irq_mask) + move.4 a3, %lo(ldsr_soft_irq_mask)(a3) + + /* + * Now re-enable interrupts for this thread and then + * wakeup the LDSR. + */ + and.4 scratchpad1, scratchpad1, d3 + move.4 int_set0, a3 + + /* + * Restore the registers. + */ + move.4 a3, (sp)4++ + move.4 d3, (sp)4++ +.endm + +/* + * ret_from_interrupt_to_kernel() + * RFI function that is where do_IRQ() returns to if the thread was + * in kernel space. + */ + .section .text.ret_from_interrupt_to_kernel, "ax", @progbits + .global ret_from_interrupt_to_kernel +ret_from_interrupt_to_kernel: + begin_restore_context ; Restore the thread context + atomic_lock_acquire ; Enter critical section + complete_restore_context ; Restore the thread context + atomic_lock_release ; Leave critical section + ldsr_thread_enable_interrupts ; enable the threads interrupts + move.4 csr, (sp)4++ ; Restore csr from the stack + ret (sp)4++ + +/* + * ret_from_interrupt_to_user() + * RFI function that is where do_IRQ() returns to if the thread was + * in user space. + * + * TODO: Do we really need the critical section handling in this code? + * + */ + .section .text.ret_from_interrupt_to_user, "ax", @progbits + .global ret_from_interrupt_to_user +ret_from_interrupt_to_user: + ldsr_thread_enable_interrupts ; enable the threads interrupts + /* + * Set a1 to the thread info pointer, no need to save it as we are + * restoring userspace and will never return + */ + movei d0, #(~(ASM_THREAD_SIZE-1)) + and.4 a1, sp, d0 + + /* + * Test if the scheduler needs to be called. + */ + btst TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED + jmpeq.t 2f + call a5, schedule ; Call the scheduler. I will come back here. + + /* + * See if we have pending signals and call do_signal + * if needed. + */ +2: + btst TI_FLAGS(a1), #ASM_TIF_SIGPENDING ; Any signals needed? + jmpeq.t 1f + + /* + * Now call do_signal() + */ + move.4 d0, #0 ; oldset pointer is NULL + move.4 d1, sp ; d1 is the regs pointer + call a5, do_signal ; Call do_signal() + + /* + * Back from do_signal(), re-enter critical section. + */ +1: + begin_restore_context ; Restore the thread context + atomic_lock_acquire ; Enter critical section + call a3, __complete_and_return_to_userspace ; jump to unprotected section + +/* + * restore_all_registers() + * + * restore_all_registers will be the alternate exit route for + * preempted processes that have called a signal handler + * and are returning back to user space. + */ + .section .text.restore_all_registers, "ax", @progbits + .global restore_all_registers +restore_all_registers: + begin_restore_context ; Restore the thread context + atomic_lock_acquire ; Enter critical section + call a3, __complete_and_return_to_userspace + +/* + * __complete_and_return_to_userspace + * + * restores the second half of the context and returns + * You must have the atomic lock when you call this function + */ + .section .kernel_unprotected, "ax", @progbits +__complete_and_return_to_userspace: + disable_kernel_ranges_for_current d15 ; disable kernel ranges + complete_restore_context ; restore previous context + atomic_lock_release ; Leave critical section + move.4 csr, (sp)4++ ; Restore csr from the stack + ret (sp)4++ + +/* + * ret_from_fork() + * Called on the child's return from fork system call. + */ + .section .text.ret_from_fork, "ax", @progbits + .global ret_from_fork +ret_from_fork: + ;;; d0 contains the arg for schedule_tail + ;;; the others we don't care about as they are in PT_REGS (sp) + call a5, schedule_tail + + atomic_lock_acquire ; Enter critical section + + move.4 a3, sp + move.4 d0, PT_D0(a3) ; Restore D0 + move.4 d1, PT_D1(a3) ; Restore D1 + move.4 d2, PT_D2(a3) ; Restore D2 + move.4 d3, PT_D3(a3) ; Restore D3 + move.4 d10, PT_D10(a3) ; Restore D10 + move.4 d11, PT_D11(a3) ; Restore D11 + move.4 d12, PT_D12(a3) ; Restore D12 + move.4 d13, PT_D13(a3) ; Restore D13 + move.4 a1, PT_A1(a3) ; Restore A1 + move.4 a2, PT_A2(a3) ; Restore A2 + move.4 a5, PT_A5(a3) ; Restore A5 + move.4 a6, PT_A6(a3) ; Restore A6 + ;; I think atomic_lock_acquire could be moved here.. + move.4 sp, PT_SP(a3) ; Restore sp + move.4 a4, PT_PC(a3) ; Restore pc in register a4 + move.4 PT_FRAME_TYPE(a3), #0 ; Clear frame_type to indicate it is invalid. + +#ifdef CONFIG_PROTECT_KERNEL + call a3, __ret_from_fork_bottom_half + .section .kernel_unprotected, "ax", @progbits +__ret_from_fork_bottom_half: + disable_kernel_ranges_for_current d15 +#endif + atomic_lock_release ; Leave critical section + calli a4, 0(a4) ; Return. + +/* + * __switch_to() + * + * Call with: + * void *__switch_to(struct task_struct *prev, struct thread_struct *prev_switch, + * struct thread_struct *next_switch) + */ + .section .text.__switch_to, "ax", @progbits + .global __switch_to +__switch_to: + + /* + * Set up register a3 to point to save area. + */ + movea a3, d1 ; a3 now holds prev_switch + move.4 (a3)4++, d10 + move.4 (a3)4++, d11 + move.4 (a3)4++, d12 + move.4 (a3)4++, d13 + move.4 (a3)4++, a1 + move.4 (a3)4++, a2 + move.4 (a3)4++, a5 + move.4 (a3)4++, a6 + move.4 (a3)4++, a7 + + /* + * Set up register a3 to point to restore area. + */ + movea a3, d2 ; a3 now holds next_switch + move.4 d10 , (a3)4++ + move.4 d11 , (a3)4++ + move.4 d12 , (a3)4++ + move.4 d13 , (a3)4++ + move.4 a1 , (a3)4++ + move.4 a2 , (a3)4++ + move.4 a5 , (a3)4++ + move.4 a6 , (a3)4++ + move.4 a7 , (a3)4++ + + /* + * Load the sw_ksp with the proper thread_info pointer. + */ + movei d15, #(~(ASM_THREAD_SIZE-1)) + and.4 a3, sp, d15 ; a3 now has the thread info pointer + moveai a4, #%hi(sw_ksp) + lea.1 a4, %lo(sw_ksp)(a4) ; a4 now has the base address of sw_ksp array + lsr.4 d15, ROSR, #2 ; Thread number - bit's 6 through 31 are zeroes anyway. + move.4 (a4, d15), a3 ; Load the thread info pointer into the hw_ksp array.. + + /* + * We are done with context switch. Time to return.. + */ + calli a5, 0(a5) + .size __switch_to, . - __switch_to + +/* + * ubicom32_emulate_insn() + * Emulates the instruction. + * + * Call with: + * unsigned int ubicom32_emulate_insn(int source1, int source2, int source3, int *save_acc, int *save_csr); + */ + .section .text.ubicom32_emulate_insn, "ax", @progbits + .global ubicom32_emulate_insn + .global trap_emulate +ubicom32_emulate_insn: + movea a3, d3 ; a3 holds save_acc pointer + movea a4, d4 ; a4 hods save_csr pointer + move.4 source3, d2 + move.4 acc0_lo, (a3) + move.4 acc0_hi, 4(a3) + move.4 acc1_lo, 8(a3) + move.4 acc1_hi, 12(a3) + move.4 mac_rc16, 16(a3) + move.4 CSR, (a4) + setcsr_flush 0 + +trap_emulate: + move.4 d0, d1 + setcsr_flush 0 + move.4 (a4), CSR ; Save csr + move.4 (a3), acc0_lo + move.4 4(a3), acc0_hi + move.4 8(a3), acc1_lo + move.4 12(a3), acc1_hi + move.4 16(a3), mac_rc16 + ret a5 + .size ubicom32_emulate_insn, . - ubicom32_emulate_insn diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_ksyms.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_ksyms.c new file mode 100644 index 000000000..ea7eb1575 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_ksyms.c @@ -0,0 +1,98 @@ +/* + * arch/ubicom32/kernel/ubicom32_ksyms.c + * Ubicom32 architecture compiler support and misc symbols. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* platform dependent support */ + +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); + +EXPORT_SYMBOL(ip_fast_csum); + + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy_nocheck); + +/* The following are special because they're not called + explicitly (the C compiler generates them). Fortunately, + their interface isn't gonna change any time soon now, so + it's OK to leave it out of version control. */ +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); + +#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4 +/* + * libgcc functions - functions that are used internally by the + * compiler... (prototypes are not correct though, but that + * doesn't really matter since they're not versioned). + */ +extern void __ashldi3(void); +extern void __ashrdi3(void); +extern void __divsi3(void); +extern void __divdi3(void); +extern void __lshrdi3(void); +extern void __modsi3(void); +extern void __muldi3(void); +extern void __udivsi3(void); +extern void __umodsi3(void); + +/* gcc lib functions */ +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__divdi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umodsi3); +#else +extern void __libgcc_udivmodsi(void); +extern void __libgcc_divmodsi(void); + +EXPORT_SYMBOL(__libgcc_udivmodsi); +EXPORT_SYMBOL(__libgcc_divmodsi); +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_syscall.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_syscall.S new file mode 100644 index 000000000..870f66c8f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_syscall.S @@ -0,0 +1,694 @@ +/* + * arch/ubicom32/kernel/ubicom32_syscall.S + * + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include + +#include +#include +#include +#include + +/* + * __old_system_call() + */ + .section .old_syscall_entry.text, "ax", @progbits +#ifdef CONFIG_OLD_40400010_SYSTEM_CALL +__old_system_call: + call a3, system_call + .size __old_system_call, . - __old_system_call ; +#else + /* + * something that will crash the userspace application, but + * should not take down the kernel, if protection is enabled + * this will never even get executed. + */ + .long 0xFABBCCDE ; illegal instruction + bkpt #-1 ; we will never get here +#endif + +/* + * system_call() + */ + .section .syscall_entry.text, "ax", @progbits + .global system_call +system_call: + /* + * Regular ABI rules for function calls apply for syscall. d8 holds + * the syscall number. We will use that to index into the syscall table. + * d0 - d5 hold the parameters. + * + * First we get the current thread_info and swap to the kernel stack. + * This is done by reading the current thread and looking up the ksp + * from the sw_ksp array and storing it in a3. + * + * Then we reserve space for the syscall context a struct pt_regs and + * save it using a4 initially and later as sp. + * Once sp is set to the kernel sp we can leave the critical section. + * + * For the user case the kernel stack will have the following layout. + * + * a3 ksp[0] +-----------------------+ + * | Thread info area | + * | struct thread_info | + * +-----------------------+ + * : : + * | Kernel Stack Area | + * | | + * a4 / sp >>> +-----------------------+ + * | Context save area | + * | struct pt_reg | + * ksp[THREAD_SIZE-8] +-----------------------+ + * | 8 Byte Buffer Zone | + * ksp[THREAD_SIZE] +-----------------------+ + + * + * For kernel syscalls the layout is as follows. + * + * a3 ksp[0] +-----------------------+ + * | Thread info area | + * | struct thread_info | + * +-----------------------+ + * : : + * | Kernel Stack Area | + * | | + * a4 / sp >>> +-----------------------+ + * | Context save area | + * | struct pt_reg | + * sp at syscall entry +-----------------------+ + * | Callers Kernel Stack | + * : : + * + * Once the context is saved we optionally call syscall_trace and setup + * the exit routine and jump to the syscall. + */ + + /* + * load the base address for sw_ksp into a3 + * Note.. we cannot access it just yet as protection is still on. + */ + moveai a3, #%hi(sw_ksp) + lea.1 a3, %lo(sw_ksp)(a3) + + /* + * Enter critical section . + * + * The 'critical' aspects here are the switching the to the ksp and + * changing the protection registers, these both use per thread + * information so we need to protect from a context switch. For now this + * is done using the global atomic lock. + */ + atomic_lock_acquire + + thread_get_self d15 ; Load current thread number +#ifdef CONFIG_PROTECT_KERNEL + lsl.4 d9, #1, d15 ; Convert to thread bit + enable_kernel_ranges d9 +#endif + /* + * in order to reduce the size of code in the syscall section we get + * out of it right now + */ + call a4, __system_call_bottom_half + .size system_call, . - system_call + + .section .text.__system_call_bottom_half, "ax", @progbits +__system_call_bottom_half: + + /* + * We need to Determine if this is a kernel syscall or user syscall. + * Start by loading the pointer for the thread_info structure for the + * current process in to a3. + */ + move.4 a3, (a3, d15) ; a3 = sw_ksp[d15] + + /* + * Now if this is a kernel thread the same value can be a acheived by + * masking off the lower bits on the current stack pointer. + */ + movei d9, #(~(ASM_THREAD_SIZE-1)) ; load mask + and.4 d9, sp, d9 ; apply mask + + /* + * d9 now has the masked version of the sp. If this is identical to + * what is in a3 then don't switch to ksp as we are already in the + * kernel. + */ + sub.4 #0, a3, d9 + + /* + * if d9 and a3 are not equal. We are usespace and have to shift to + * ksp. + */ + jmpne.t 1f + + /* + * Kernel Syscall. + * + * The kernel has called this routine. We have to pdec space for pt_regs + * from sp. + */ + pdec a4, PT_SIZE(sp) ; a4 = ksp - PT_SIZE + jmpt.t 2f + + /* + * Userspace Syscall. + * + * Add THREAD_SIZE and subtract PT_SIZE to create the proper ksp + */ +1: movei d15, #(ASM_THREAD_SIZE - 8 - PT_SIZE) + lea.1 a4, (a3, d15) ; a4 = ksp + d15 + + /* + * Replace user stack pointer with kernel stack pointer (a4) + * Load -1 into frame_type in save area to indicate this is system call + * frame. + */ +2: move.4 PT_A7(a4), a7 ; Save old sp/A7 on kernel stack + move.4 PT_FRAME_TYPE(a4), #-1 ; Set the frame type. + move.4 sp, a4 ; Change to ksp. + /* + * We are now officially back in the kernel! + */ + + /* + * Now that we are on the ksp we can leave the critical section + */ + atomic_lock_release + + /* + * We need to save a0 because we need to be able to restore it in + * the event that we need to handle a signal. It's not generally + * a callee-saved register but is the GOT pointer. + */ + move.4 PT_A0(sp), a0 ; Save A0 on kernel stack + + /* + * We still need to save d10-d13, a1, a2, a5, a6 in the kernel frame + * for this process, we also save the system call params in the case of + * syscall restart. (note a7 was saved above) + */ + move.4 PT_A1(sp), a1 ; Save A1 on kernel stack + move.4 PT_A2(sp), a2 ; Save A2 on kernel stack + move.4 PT_A5(sp), a5 ; Save A5 on kernel stack + move.4 PT_A6(sp), a6 ; Save A6 on kernel stack + move.4 PT_PC(sp), a5 ; Save A5 at the PC location + move.4 PT_D10(sp), d10 ; Save D10 on kernel stack + move.4 PT_D11(sp), d11 ; Save D11 on kernel stack + move.4 PT_D12(sp), d12 ; Save D12 on kernel stack + move.4 PT_D13(sp), d13 ; Save D13 on kernel stack + + /* + * Now save the syscall parameters + */ + move.4 PT_D0(sp), d0 ; Save d0 on kernel stack + move.4 PT_ORIGINAL_D0(sp), d0 ; Save d0 on kernel stack + move.4 PT_D1(sp), d1 ; Save d1 on kernel stack + move.4 PT_D2(sp), d2 ; Save d2 on kernel stack + move.4 PT_D3(sp), d3 ; Save d3 on kernel stack + move.4 PT_D4(sp), d4 ; Save d4 on kernel stack + move.4 PT_D5(sp), d5 ; Save d5 on kernel stack + move.4 PT_D8(sp), d8 ; Save d8 on kernel stack + + /* + * Test if syscalls are being traced and if they are jump to syscall + * trace (it will comeback here) + */ + btst TI_FLAGS(a3), #ASM_TIF_SYSCALL_TRACE + jmpne.f .Lsystem_call__trace +.Lsystem_call__trace_complete: + /* + * Check for a valid call number [ 0 <= syscall_number < NR_syscalls ] + */ + cmpi d8, #0 + jmplt.f 3f + cmpi d8, #NR_syscalls + jmplt.t 4f + + /* + * They have passed an invalid number. Call sys_ni_syscall staring by + * load a4 with the base address of sys_ni_syscall + */ +3: moveai a4, #%hi(sys_ni_syscall) + lea.1 a4, %lo(sys_ni_syscall)(a4) + jmpt.t 5f ; Jump to regular processing + + /* + * Validated syscall, load the syscall table base address into a3 and + * read the syscall ptr out. + */ +4: moveai a3, #%hi(sys_call_table) + lea.1 a3, %lo(sys_call_table)(a3) ; a3 = sys_call_table + move.4 a4, (a3, d8) ; a4 = sys_call_table[d8] + + /* + * Before calling the syscall, setup a5 so that syscall_exit is called + * on return from syscall + */ +5: moveai a5, #%hi(syscall_exit) ; Setup return address + lea.1 a5, %lo(syscall_exit)(a5) ; from system call + + /* + * If the syscall is __NR_rt_rigreturn then we have to test d1 to + * figure out if we have to change change the return routine to restore + * all registers. + */ + cmpi d8, #__NR_rt_sigreturn + jmpeq.f 6f + + /* + * Launch system call (it will return through a5 - syscall_exit) + */ + calli a3, 0(a4) + + /* + * System call is rt_sigreturn. Test d1. If it is 1 we have to + * change the return address to restore_all_registers + */ +6: cmpi d1, #1 + jmpne.t 7f + + moveai a5, #%hi(restore_all_registers) ; Setup return address + lea.1 a5, %lo(restore_all_registers)(a5) ; to restore_all_registers. + + /* + * Launch system call (it will return through a5) + */ +7: calli a3, 0(a4) ; Launch system call + +.Lsystem_call__trace: + /* + * Syscalls are being traced. + * Call syscall_trace, (return here) + */ + call a5, syscall_trace + + /* + * Restore syscall state (it would have been discarded during the + * syscall trace) + */ + move.4 d0, PT_D0(sp) ; Restore d0 from kernel stack + move.4 d1, PT_D1(sp) ; Restore d1 from kernel stack + move.4 d2, PT_D2(sp) ; Restore d2 from kernel stack + move.4 d3, PT_D3(sp) ; Restore d3 from kernel stack + move.4 d4, PT_D4(sp) ; Restore d4 from kernel stack + move.4 d5, PT_D5(sp) ; Restore d5 from kernel stack + /* add this back if we ever have a syscall with 7 args */ + move.4 d8, PT_D8(sp) ; Restore d8 from kernel stack + + /* + * return to syscall + */ + jmpt.t .Lsystem_call__trace_complete + .size __system_call_bottom_half, . - __system_call_bottom_half + +/* + * syscall_exit() + */ + .section .text.syscall_exit + .global syscall_exit +syscall_exit: + /* + * d0 contains the return value. We should move that into the kernel + * stack d0 location. We will be transitioning from kernel to user + * mode. Test the flags and see if we have to call schedule. If we are + * going to truly exit then all that has to be done is that from the + * kernel stack we have to restore d0, a0, a1, a2, a5, a6 and sp (a7)bb + * and then return via a5. + */ + + /* + * Save d0 to pt_regs + */ + move.4 PT_D0(sp), d0 ; Save d0 into the kernel stack + + /* + * load the thread_info structure by masking off the THREAD_SIZE + * bits. + * + * Note: we used to push a1, but now we don't as we are going + * to eventually restore it to the userspace a1. + */ + movei d9, #(~(ASM_THREAD_SIZE-1)) + and.4 a1, sp, d9 + + /* + * Are any interesting bits set on TI flags, if there are jump + * aside to post_processing. + */ + move.4 d9, #(_TIF_SYSCALL_TRACE | _TIF_NEED_RESCHED | _TIF_SIGPENDING) + and.4 #0, TI_FLAGS(a1), d9 + jmpne.f .Lsyscall_exit__post_processing ; jump to handler +.Lsyscall_exit__post_processing_complete: + + move.4 d0, PT_D0(sp) ; Restore D0 from kernel stack + move.4 d1, PT_D1(sp) ; Restore d1 from kernel stack + move.4 d2, PT_D2(sp) ; Restore d2 from kernel stack + move.4 d3, PT_D3(sp) ; Restore d3 from kernel stack + move.4 d4, PT_D4(sp) ; Restore d4 from kernel stack + move.4 d5, PT_D5(sp) ; Restore d5 from kernel stack + move.4 d8, PT_D8(sp) ; Restore d8 from kernel stack + move.4 d10, PT_D10(sp) ; Restore d10 from kernel stack + move.4 d11, PT_D11(sp) ; Restore d11 from kernel stack + move.4 d12, PT_D12(sp) ; Restore d12 from kernel stack + move.4 d13, PT_D13(sp) ; Restore d13 from kernel stack + move.4 a1, PT_A1(sp) ; Restore A1 from kernel stack + move.4 a2, PT_A2(sp) ; Restore A2 from kernel stack + move.4 a5, PT_A5(sp) ; Restore A5 from kernel stack + move.4 a6, PT_A6(sp) ; Restore A6 from kernel stack + move.4 a0, PT_A0(sp) ; Restore A6 from kernel stack + + /* + * this is only for debug, and could be removed for production builds + */ + move.4 PT_FRAME_TYPE(sp), #0 ; invalidate frame_type + +#ifdef CONFIG_PROTECT_KERNEL + + call a4, __syscall_exit_bottom_half + + .section .kernel_unprotected, "ax", @progbits +__syscall_exit_bottom_half: + /* + * Enter critical section + */ + atomic_lock_acquire + disable_kernel_ranges_for_current d15 +#endif + /* + * Lastly restore userspace stack ptr + * + * Note: that when protection is on we need to hold the lock around the + * stack swap as well because otherwise the protection could get + * inadvertently disabled again at the end of a context switch. + */ + move.4 a7, PT_A7(sp) ; Restore A7 from kernel stack + + /* + * We are now officially back in userspace! + */ + +#ifdef CONFIG_PROTECT_KERNEL + /* + * Leave critical section and return to user space. + */ + atomic_lock_release +#endif + calli a5, 0(a5) ; Back to userspace code. + + bkpt #-1 ; we will never get here + + /* + * Post syscall processing. (unlikely part of syscall_exit) + * + * Are we tracing syscalls. If TIF_SYSCALL_TRACE is set, call + * syscall_trace routine and return here. + */ + .section .text.syscall_exit, "ax", @progbits +.Lsyscall_exit__post_processing: + btst TI_FLAGS(a1), #ASM_TIF_SYSCALL_TRACE + jmpeq.t 1f + call a5, syscall_trace + + /* + * Do we need to resched ie call schedule. If TIF_NEED_RESCHED is set, + * call the scheduler, it will come back here. + */ +1: btst TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED + jmpeq.t 2f + call a5, schedule + + /* + * Do we need to post a signal, if TIF_SIGPENDING is set call the + * do_signal. + */ +2: btst TI_FLAGS(a1), #ASM_TIF_SIGPENDING + jmpeq.t .Lsyscall_exit__post_processing_complete + + /* + * setup the do signal call + */ + move.4 d0, #0 ; oldset pointer is NULL + lea.1 d1, (sp) ; d1 is the regs pointer. + call a5, do_signal + + jmpt.t .Lsyscall_exit__post_processing_complete + +/* .size syscall_exit, . - syscall_exit */ + +/* + * kernel_execve() + * kernel_execv is called when we the kernel is starting a + * userspace application. + */ + .section .kernel_unprotected, "ax", @progbits + .global kernel_execve +kernel_execve: + move.4 -4(sp)++, a5 ; Save return address + /* + * Call execve + */ + movei d8, #__NR_execve ; call execve + call a5, system_call + move.4 a5, (sp)4++ + + /* + * protection was enabled again at syscall exit, but we want + * to return to kernel so we enable it again. + */ +#ifdef CONFIG_PROTECT_KERNEL + /* + * We are entering the kernel so we need to disable the protection. + * Enter critical section, disable ranges and leave critical section. + */ + call a3, __enable_kernel_ranges ; and jump back to kernel +#else + ret a5 ; jump back to the kernel +#endif + + .size kernel_execve, . - kernel_execve + +/* + * signal_trampoline() + * + * Deals with transitioning from to userspace signal handlers and returning + * to userspace, only called from the kernel. + * + */ + .section .kernel_unprotected, "ax", @progbits + .global signal_trampoline +signal_trampoline: + /* + * signal_trampoline is called when we are jumping from the kernel to + * the userspace signal handler. + * + * The following registers are relevant. (set setup_rt_frame) + * sp is the user space stack not the kernel stack + * d0 = signal number + * d1 = siginfo_t * + * d2 = ucontext * + * d3 = the user space signal handler + * a0 is set to the GOT if userspace application is FDPIC, otherwise 0 + * a3 is set to the FD for the signal if userspace application is FDPIC + */ +#ifdef CONFIG_PROTECT_KERNEL + /* + * We are leaving the kernel so we need to enable the protection. + * Enter critical section, disable ranges and leave critical section. + */ + atomic_lock_acquire ; Enter critical section + disable_kernel_ranges_for_current d15 ; disable kernel ranges + atomic_lock_release ; Leave critical section +#endif + /* + * The signal handler pointer is in register d3 so tranfer it to a4 and + * call it + */ + movea a4, d3 ; signal handler + calli a5, 0(a4) + + /* + * Return to userspace through rt_syscall which is stored on top of the + * stack d1 contains ret_via_interrupt status. + */ + move.4 d8, (sp) ; d8 (syscall #) = rt_syscall + move.4 d1, 4(sp) ; d1 = ret_via_interrupt + call a5, system_call ; as we are 'in' the kernel + ; we can call kernel_syscall + + bkpt #-1 ; will never get here. + .size signal_trampoline, . - signal_trampoline + +/* + * kernel_thread_helper() + * + * Entry point for kernel threads (only referenced by kernel_thread()). + * + * On execution d0 will be 0, d1 will be the argument to be passed to the + * kernel function. + * d2 contains the kernel function that needs to get called. + * d3 will contain address to do_exit which needs to get moved into a5. + * + * On return from fork the child thread d0 will be 0. We call this dummy + * function which in turn loads the argument + */ + .section .kernel_unprotected, "ax", @progbits + .global kernel_thread_helper +kernel_thread_helper: + /* + * Create a kernel thread. This is called from ret_from_vfork (a + * userspace return routine) so we need to put it in an unprotected + * section and re-enable protection before calling the vector in d2. + */ + +#ifdef CONFIG_PROTECT_KERNEL + /* + * We are entering the kernel so we need to disable the protection. + * Enter critical section, disable ranges and leave critical section. + */ + call a5, __enable_kernel_ranges +#endif + /* + * Move argument for kernel function into d0, and set a5 return address + * (a5) to do_exit and return through a2 + */ + move.4 d0, d1 ; d0 = arg + move.4 a5, d3 ; a5 = do_exit + ret d2 ; call function ptr in d2 + .size kernel_thread_helper, . - kernel_thread_helper + +#ifdef CONFIG_PROTECT_KERNEL + .section .kernel_unprotected, "ax", @progbits +__enable_kernel_ranges: + atomic_lock_acquire ; Enter critical section + enable_kernel_ranges_for_current d15 + atomic_lock_release ; Leave critical section + calli a5, 0(a5) + .size __enable_kernel_ranges, . - __enable_kernel_ranges + +#endif + +/* + * The following system call intercept functions where we setup the + * input to the real system call. In all cases these are just taking + * the current sp which is pointing to pt_regs and pushing it into the + * last arg of the system call. + * + * i.e. the public definition of sys_execv is + * sys_execve( char *name, + * char **argv, + * char **envp ) + * but process.c defines it as + * sys_execve( char *name, + * char **argv, + * char **envp, + * struct pt_regs *regs ) + * + * so execve_intercept needs to populate the 4th arg with pt_regs*, + * which is the stack pointer as we know we must be coming out of + * system_call + * + * The intercept vectors are referenced by syscalltable.S + */ + +/* + * execve_intercept() + */ + .section .text.execve_intercept, "ax", @progbits + .global execve_intercept +execve_intercept: + move.4 d3, sp ; Save pt_regs address + call a3, sys_execve + + .size execve_intercept, . - execve_intercept + +/* + * vfork_intercept() + */ + .section .text.vfork_intercept, "ax", @progbits + .global vfork_intercept +vfork_intercept: + move.4 d0, sp ; Save pt_regs address + call a3, sys_vfork + + .size vfork_intercept, . - vfork_intercept + +/* + * clone_intercept() + */ + .section .text.clone_intercept, "ax", @progbits + .global clone_intercept +clone_intercept: + move.4 d2, sp ; Save pt_regs address + call a3, sys_clone + + .size clone_intercept, . - clone_intercept + +/* + * sys_sigsuspend() + */ + .section .text.sigclone_intercept, "ax", @progbits + .global sys_sigsuspend +sys_sigsuspend: + move.4 d0, sp ; Pass pointer to pt_regs in d0 + call a3, do_sigsuspend + + .size sys_sigsuspend, . - sys_sigsuspend + +/* + * sys_rt_sigsuspend() + */ + .section .text.sys_rt_sigsuspend, "ax", @progbits + .global sys_rt_sigsuspend +sys_rt_sigsuspend: + move.4 d0, sp ; Pass pointer to pt_regs in d0 + call a3, do_rt_sigsuspend + + .size sys_rt_sigsuspend, . - sys_rt_sigsuspend + +/* + * sys_rt_sigreturn() + */ + .section .text.sys_rt_sigreturn, "ax", @progbits + .global sys_rt_sigreturn +sys_rt_sigreturn: + move.4 d0, sp ; Pass pointer to pt_regs in d0 + call a3, do_rt_sigreturn + + .size sys_rt_sigreturn, . - sys_rt_sigreturn + +/* + * sys_sigaltstack() + */ + .section .text.sys_sigaltstack, "ax", @progbits + .global sys_sigaltstack +sys_sigaltstack: + move.4 d0, sp ; Pass pointer to pt_regs in d0 + call a3, do_sys_sigaltstack + + .size sys_sigaltstack, . - sys_sigaltstack diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/unaligned_trap.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/unaligned_trap.c new file mode 100644 index 000000000..d856d061d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/unaligned_trap.c @@ -0,0 +1,698 @@ +/* + * arch/ubicom32/kernel/unaligned_trap.c + * Handle unaligned traps in both user or kernel space. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include + +#define FALSE 0 +#define TRUE 1 + +/* no possible trap */ +#define UNUSED 0 +/* possible source operand trap */ +#define SRC 1 +#define SRC_2 2 +/* possible destination operand trap */ +#define DEST 3 +#define DEST_2 4 +/* can be either source or destination or both */ +#define TWO_OP 5 +#define TWO_OP_2 6 + +/* TODO: What is the real value here, put something in to make it compile for + * now */ +#define MOVE_2 0x0d +#define LSL_2 0x11 +#define LSR_2 0x13 +#define MOVEI 0x19 +#define CMPI 0x18 + +static int op_format[32] = +{ + TWO_OP, /* 0x00 */ + UNUSED, + SRC, + UNUSED, + TWO_OP, /* 0x04 */ + TWO_OP, + SRC, + UNUSED, + TWO_OP_2, /* 0x08 */ + TWO_OP, + TWO_OP_2, + TWO_OP, + TWO_OP_2, /* 0x0C */ + TWO_OP, + TWO_OP_2, + TWO_OP, + TWO_OP, /* 0x10 */ + TWO_OP_2, + TWO_OP, + TWO_OP, + UNUSED, /* 0x14 */ + UNUSED, + UNUSED, + UNUSED, + SRC_2, /* 0x18 */ + DEST_2, + UNUSED, + UNUSED, + UNUSED, /* 0x1C */ + UNUSED, + UNUSED, /* unaligned CALLI will not be fixed. */ + UNUSED +}; + +static int op_0_format[32] = +{ + UNUSED, /* 0x00 */ + UNUSED, + UNUSED, + UNUSED, + UNUSED, /* 0x04 - ret don't fix - bad ret is always wrong */ + UNUSED, + UNUSED, + UNUSED, + UNUSED, /* 0x08 */ + UNUSED, + TWO_OP, + TWO_OP_2, + TWO_OP, /* 0x0c */ + TWO_OP_2, + TWO_OP, + UNUSED, /* .1 can't trap */ + UNUSED, /* 0x10 */ + UNUSED, + SRC, + UNUSED, + UNUSED, /* 0x14 */ + TWO_OP_2, + UNUSED, + UNUSED, + UNUSED, /* 0x18 */ + UNUSED, + UNUSED, + UNUSED, + DEST, /* 0x1c */ + DEST, + DEST, + DEST, /* all lea have 32-bit destination */ +}; + +static int op_2_format[32] = +{ + UNUSED, /* 0x00 */ + UNUSED, + UNUSED, + UNUSED, + UNUSED, /* 0x04 */ + UNUSED, + SRC, + UNUSED, + UNUSED, /* 0x08 crcgen is .1 */ + UNUSED, + UNUSED, + UNUSED, + UNUSED, /* 0x0c */ + UNUSED, + UNUSED, + UNUSED, + SRC, /* 0x10 */ + SRC_2, + SRC, + SRC_2, + SRC, /* 0x14 */ + SRC_2, + SRC, + UNUSED, + UNUSED, /* 0x18 */ + UNUSED, + SRC, + UNUSED, + SRC, /* 0x1c */ + UNUSED, + SRC_2, + UNUSED, +}; + +static int op_6_format[32] = +{ + SRC_2, /* 0x00 */ + SRC_2, + SRC_2, + SRC_2, + SRC_2, /* 0x04 */ + SRC_2, + UNUSED, + SRC_2, + SRC, /* 0x08 MULS.4 */ + SRC_2, + SRC, + UNUSED, + UNUSED, /* 0x0c */ + UNUSED, + UNUSED, + UNUSED, + SRC, /* 0x10 */ + SRC_2, + SRC, + SRC_2, + UNUSED, /* 0x14 */ + UNUSED, + UNUSED, + UNUSED, + UNUSED, /* 0x18 */ + UNUSED, + UNUSED, + UNUSED, + UNUSED, /* 0x1c */ + UNUSED, + UNUSED, + UNUSED, +}; + +/* + * unaligned_get_address() + * get an address using save_an and save_dn registers, and updates save_an + * with side effects + */ +unsigned char *unaligned_get_address(int thread, int specifier, int four_byte, + unsigned int save_an[], + unsigned int save_dn[], int *write_back_an) +{ + unsigned char *address; + + int areg = (specifier >> 5) & 7; + if ((specifier >> 8) == 2) { + int offset = specifier & 0xf; + offset = ((offset << 28) >> 28); + if (likely(four_byte)) { + offset <<= 2; + } else { + offset <<= 1; + } + if (specifier & 0x10) { + address = (unsigned char *)(save_an[areg] + offset); + } else { + address = (unsigned char *)save_an[areg]; + } + save_an[areg] = save_an[areg] + offset; + + /* + * Let caller know An registers have been modified. + */ + *write_back_an = 1; + } else if ((specifier >> 8) == 3) { + int dreg = specifier & 0xf; + if (likely(four_byte)) { + address = (unsigned char *)(save_an[areg] + + (save_dn[dreg] << 2)); + } else { + address = (unsigned char *)(save_an[areg] + + (save_dn[dreg] << 1)); + } + } else { + int offset = ((specifier >> 3) & 0x60) | (specifier & 0x1f); + if (likely(four_byte)) { + address = (unsigned char *)(save_an[areg] + + (offset << 2)); + } else { + address = (unsigned char *)(save_an[areg] + + (offset << 1)); + } + } + + return address; +} + +static int save_dn[16]; +static int save_an[8]; +static int save_acc[5]; + +/* + * unaligned_emulate() + * emulate the instruction at thread's pc that has taken an unaligned data + * trap. + * + * source or destination or both might be unaligned + * the instruction must have a memory source or destination or both + * the emulated instruction is copied and executed in this thread + * + * TODO: Protection is handled outside of this function + * TODO: handling simultaneous unaligned and memory protection traps + * + * Get thread state + * the PC and instruction (and local copy, emulate_inst), and An + * and Dn registers + * All implicit soruce state (source3, CSR, accumulators) + + * if the instruction has a memory source + * Use the instruction, An and Dn registers to form src_address + * get unaligned source data from src_address (usually sign + * extended) + * (2 bytes, with or without sign extension, or 4 bytes) + * modify emulate_inst to use d0 as source + * else + * get the soure operand from one of thread's registers + * if instruction has a memory destination + * Use the instruction, An and Dn registers to form dest_address + * modify emulate_inst to use d0 as destination + * if there was a memory source + * put the source data in thread's d0 + * get the source-2 Dn operand and source 3 operand from thread + * execute modified inst + * (save it, flush caches, set up local values for implicit + * sources, execute, save explicit and implicit results) + * if inst has destination address + * copy result to dest_address, possibly unaligned, 1, 2, or 4 + * bytes + * restore thread's implicit results (modified address registers, CSR, + * accumulators) add 4 to thread's pc + */ +void unaligned_emulate(unsigned int thread) +{ + unsigned int pc; + unsigned int inst; + unsigned int op; + unsigned int subop; + int format; + unsigned int emulate_inst; + int four_byte; + int src_operand, dest_operand; + int save_csr; + int source3; + unsigned int source1; + unsigned int source_data; + unsigned char *dest_address = NULL; + int source2 = 0; + unsigned int result; + unsigned int write_back_an = 0; + unsigned int chip_id_copy; + + extern unsigned int trap_emulate; + extern unsigned int ubicom32_emulate_insn(int source1, int source2, + int source3, int *save_acc, + int *save_csr); + + /* + * get the chip_id + */ + asm volatile ( + " move.4 %0, chip_id \n\t" /* get chip_id. */ + : "=r"(chip_id_copy) + : + ); + + /* + * get the pc + */ + asm volatile ( + " move.4 CSR, %1 \n\t" /* set source thread in + * CSR */ + " setcsr_flush 0 \n\t" + " move.4 %0, pc \n\t" + " move.4 CSR, #0 \n\t" /* restore CSR */ + " setcsr_flush 0 \n\t" + : "=a"(pc) + : "d" ((1 << 8) | (thread << 9)) + : "cc" + ); + + inst = *((unsigned int *)pc); + op = inst >> 27; + if (unlikely(op == 2 || op == 6)) { + subop = (inst >> 21) & 0x1f; + } else { + subop = (inst >> 11) & 0x1f; + } + format = op_format[op]; + emulate_inst = inst; + + if (op == 0) { + format = op_0_format[subop]; + } else if (op == 2) { + format = op_2_format[subop]; + } else if (op == 6) { + format = op_6_format[subop]; + } + + if (unlikely(format == UNUSED)) { + /* + * We are not going to emulate this. Bump PC by 4 and move on. + */ + asm volatile ( + " move.4 CSR, %0 \n\t" + " setcsr_flush 0 \n\t" + " move.4 pc, %1 \n\t" + " setcsr #0 \n\t" + " setcsr_flush 0 \n\t" + : + : "d"((1 << 14) | (thread << 15)), "d"(pc + 4) + : "cc" + ); + return; + } + + four_byte = (format == TWO_OP || format == DEST || format == SRC); + + /* + * source or destination memory operand needs emulation + */ + src_operand = (format == SRC || + format == SRC_2 || + format == TWO_OP || + format == TWO_OP_2) && + ((inst >> 8) & 7) > 1; + + dest_operand = (format == DEST || + format == DEST_2 || + format == TWO_OP || + format == TWO_OP_2) && + ((inst >> 24) & 7) > 1; + + /* + * get thread's implicit sources (not covered by source context select). + * data and address registers and CSR (for flag bits) and src3 and + * accumulators + */ + asm volatile ( + " move.4 CSR, %2 \n\t" /* set source thread in + * CSR */ + " setcsr_flush 0 \n\t" + " move.4 (%3), d0 \n\t" /* get dn registers */ + " move.4 4(%3), d1 \n\t" + " move.4 8(%3), d2 \n\t" + " move.4 12(%3), d3 \n\t" + " move.4 16(%3), d4 \n\t" + " move.4 20(%3), d5 \n\t" + " move.4 24(%3), d6 \n\t" + " move.4 28(%3), d7 \n\t" + " move.4 32(%3), d8 \n\t" + " move.4 36(%3), d9 \n\t" + " move.4 40(%3), d10 \n\t" + " move.4 44(%3), d11 \n\t" + " move.4 48(%3), d12 \n\t" + " move.4 52(%3), d13 \n\t" + " move.4 56(%3), d14 \n\t" + " move.4 60(%3), d15 \n\t" + " move.4 (%4), a0 \n\t" /* get an registers */ + " move.4 4(%4), a1 \n\t" + " move.4 8(%4), a2 \n\t" + " move.4 12(%4), a3 \n\t" + " move.4 16(%4), a4 \n\t" + " move.4 20(%4), a5 \n\t" + " move.4 24(%4), a6 \n\t" + " move.4 28(%4), a7 \n\t" + " move.4 %0, CSR \n\t" /* get csr and source3 + * implicit operands */ + " move.4 %1, source3 \n\t" + " move.4 (%5), acc0_lo \n\t" /* get accumulators */ + " move.4 4(%5), acc0_hi \n\t" + " move.4 8(%5), acc1_lo \n\t" + " move.4 12(%5), acc1_hi \n\t" + " move.4 16(%5), mac_rc16 \n\t" + " move.4 CSR, #0 \n\t" /* restore CSR */ + " setcsr_flush 0 \n\t" + : "=m"(save_csr), "=m"(source3) + : "d"((1 << 8) | (thread << 9)), + "a"(save_dn), "a"(save_an), "a"(save_acc) + : "cc" + ); + + /* + * turn off thread select bits if they were on + */ + BUG_ON((save_csr & 0x04100) != 0); + if (unlikely(save_csr & 0x04100)) { + /* + * Things are in funny state as thread select bits are on in + * csr. PANIC. + */ + panic("In unaligned trap handler. Trap thread CSR has thread " + "select bits on.\n"); + } + + save_csr = save_csr & 0x1000ff; + + /* + * get the source1 operand + */ + source1 = 0; + if (src_operand) { + unsigned char *src_address; + + /* + * source1 comes from memory + */ + BUG_ON(!(format == TWO_OP || format == TWO_OP_2 || + format == SRC || format == SRC_2)); + src_address = unaligned_get_address(thread, inst & 0x7ff, + four_byte, save_an, + save_dn, &write_back_an); + + /* + * get data (possibly unaligned) + */ + if (likely(four_byte)) { + source_data = (*src_address << 24) | + (*(src_address + 1) << 16) | + (*(src_address + 2) << 8) | + *(src_address + 3); + source1 = source_data; + } else { + source1 = *src_address << 8 | + *(src_address + 1); + + /* + * Source is not extended if the instrution is MOVE.2 or + * if the cpu CHIP_ID >= 0x30000 and the instruction is + * either LSL.2 or LSR.2. All other cases have to be + * sign extended. + */ + if ((!(op == 2 && subop == MOVE_2)) && + (!((chip_id_copy >= 0x30000) && + (subop == LSL_2 || subop == LSR_2)))) { + /* + * Have to sign extend the .2 entry. + */ + source1 = ((unsigned int) + ((signed int) + ((signed short) source1))); + } + } + } else if (likely(op != MOVEI)) { + /* + * source1 comes from a register, using move.4 d0, src1 + * unaligned_emulate_get_source is pointer to code to insert remulated instruction + */ + extern unsigned int unaligned_emulate_get_src; + *((int *)&unaligned_emulate_get_src) &= ~(0x7ff); + *((int *)&unaligned_emulate_get_src) |= (inst & 0x7ff); + flush_dcache_range((unsigned long)(&unaligned_emulate_get_src), + (unsigned long)(&unaligned_emulate_get_src) + 4); + + asm volatile ( + /* source1 uses thread's registers */ + " move.4 CSR, %1 \n\t" + " setcsr_flush 0 \n\t" + "unaligned_emulate_get_src: \n\t" + " move.4 %0, #0 \n\t" + " setcsr #0 \n\t" + " setcsr_flush 0 \n\t" + : "=d" (source1) + : "d" ((1 << 8) | (thread << 9)) + : "cc" + ); + } + + /* + * get the destination address + */ + if (dest_operand) { + BUG_ON(!(format == TWO_OP || format == TWO_OP_2 || + format == DEST || format == DEST_2)); + dest_address = unaligned_get_address(thread, + ((inst >> 16) & 0x7ff), + four_byte, save_an, + save_dn, &write_back_an); + } + + if (write_back_an) { + /* + * restore any modified An registers + */ + asm volatile ( + " move.4 CSR, %0 \n\t" + " setcsr_flush 0 \n\t" + " move.4 a0, (%1) \n\t" + " move.4 a1, 4(%1) \n\t" + " move.4 a2, 8(%1) \n\t" + " move.4 a3, 12(%1) \n\t" + " move.4 a4, 16(%1) \n\t" + " move.4 a5, 20(%1) \n\t" + " move.4 a6, 24(%1) \n\t" + " move.4 a7, 28(%1) \n\t" + " setcsr #0 \n\t" + " setcsr_flush 0 \n\t" + : + : "d" ((1 << 14) | (thread << 15)), "a" (save_an) + : "cc" + ); + } + + /* + * get source 2 register if needed, and modify inst to use d1 for + * source-2 source-2 will come from this thread, not the trapping thread + */ + source2 = 0; + if ((op >= 8 && op <= 0x17) || + ((op == 2 || op == 6) && (inst & 0x4000000))) { + int src_dn = (inst >> 11) & 0xf; + source2 = save_dn[src_dn]; + /* + * force the emulated instruction to use d1 for source2 operand + */ + emulate_inst = (emulate_inst & 0xffff07ff) | 0x800; + } + + if (likely(op != MOVEI)) { + /* + * change emulated instruction source1 to d0 + */ + emulate_inst &= ~0x7ff; + emulate_inst |= 1 << 8; + } + + if (unlikely(op == 6 || op == 2)) { + /* + * Set destination to d0 + */ + emulate_inst &= ~(0xf << 16); + } else if (likely(op != CMPI)) { + /* + * Set general destination field to d0. + */ + emulate_inst &= ~(0x7ff << 16); + emulate_inst |= 1 << 24; + } + + /* + * execute emulated instruction d0, to d0, no memory access + * source2 if needed will be in d1 + * source3, CSR, and accumulators are set up before execution + */ + *((unsigned int *)&trap_emulate) = emulate_inst; + flush_dcache_range((unsigned long)(&trap_emulate), + (unsigned long)(&trap_emulate) + 4); + + result = ubicom32_emulate_insn(source1, source2, source3, + save_acc, &save_csr); + + /* + * set the result value + */ + if (dest_operand) { + /* + * copy result to memory + */ + if (four_byte) { + *dest_address++ = + (unsigned char)((result >> 24) & 0xff); + *dest_address++ = + (unsigned char)((result >> 16) & 0xff); + } + *dest_address++ = (unsigned char)((result >> 8) & 0xff); + *dest_address = (unsigned char)(result & 0xff); + } else if (likely(op != CMPI)) { + /* + * copy result to a register, using move.4 dest, result + */ + extern unsigned int unaligned_trap_set_result; + *((unsigned int *)&unaligned_trap_set_result) &= ~0x7ff0000; + + if (op == 2 || op == 6) { + *((unsigned int *)&unaligned_trap_set_result) |= + ((inst & 0x000f0000) | 0x01000000); + } else { + *((unsigned int *)&unaligned_trap_set_result) |= + (inst & 0x7ff0000); + } + flush_dcache_range((unsigned long)&unaligned_trap_set_result, + ((unsigned long)(&unaligned_trap_set_result) + 4)); + + asm volatile ( + /* result uses thread's registers */ + " move.4 CSR, %1 \n\t" + " setcsr_flush 0 \n\t" + "unaligned_trap_set_result: \n\t" + " move.4 #0, %0 \n\t" + " setcsr #0 \n\t" + " setcsr_flush 0 \n\t" + : + : "d"(result), "d" ((1 << 14) | (thread << 15)) + : "cc" + ); + } + + /* + * bump PC in thread and restore implicit register changes + */ + asm volatile ( + " move.4 CSR, %0 \n\t" + " setcsr_flush 0 \n\t" + " move.4 pc, %1 \n\t" + " move.4 acc0_lo, (%3) \n\t" + " move.4 acc0_hi, 4(%3) \n\t" + " move.4 acc1_lo, 8(%3) \n\t" + " move.4 acc1_hi, 12(%3) \n\t" + " move.4 mac_rc16, 16(%3) \n\t" + " move.4 CSR, %2 \n\t" + " setcsr #0 \n\t" + " setcsr_flush 0 \n\t" + : + : "d"((1 << 14) | (thread << 15)), + "d"(pc + 4), "d"(save_csr), "a"(save_acc) + : "cc" + ); +} + +/* + * unaligned_only() + * Return true if either of the unaligned causes are set (and no others). + */ +int unaligned_only(unsigned int cause) +{ + unsigned int unaligned_cause_mask = + (1 << TRAP_CAUSE_DST_MISALIGNED) | + (1 << TRAP_CAUSE_SRC1_MISALIGNED); + + BUG_ON(cause == 0); + return (cause & unaligned_cause_mask) == cause; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/vmlinux.lds.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/vmlinux.lds.S new file mode 100644 index 000000000..cd646772c --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/vmlinux.lds.S @@ -0,0 +1,370 @@ +/* + * arch/ubicom32/kernel/vmlinux.lds.S + * vmlinux primary linker script + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include + +/* + * Sanity checks to prevent errors later on that are much harder to understand + */ +#if !defined APP_OCM_CODE_SIZE +#error APP_OCM_CODE_SIZE has not been defined in ocm_size.h +#endif + +#if !defined APP_OCM_DATA_SIZE +#error APP_OCM_DATA_SIZE has not been defined in ocm_size.h +#endif + +/* + * The `free' ocm area that ultra does not use. + */ +#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE +#define OCM_FREE_START (OCMSTART + APP_OCM_CODE_SIZE) +#define OCM_FREE_LENGTH (OCMSIZE - APP_OCM_CODE_SIZE - APP_OCM_DATA_SIZE) +#else +#define OCM_FREE_START OCMEND +#define OCM_FREE_LENGTH 0 +#endif + +/* + * If you want to limit OCM use for text/data or completely disable it + * you can change these values. + */ +#define OCM_TEXT_LENGTH OCM_FREE_LENGTH +#define OCM_DATA_LENGTH OCM_FREE_LENGTH + +#define RAM_START KERNELSTART +#define RAM_LENGTH ((SDRAMSTART + CONFIG_MIN_RAMSIZE) - RAM_START) +#define TEXT ram +#define DATA ram +#define INIT ram +#define BSS ram + +#ifndef DATA_ADDR +#define DATA_ADDR +#endif + +#include + +OUTPUT_ARCH(ubicom32) +ENTRY(_start) + +MEMORY { + ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH + syscall : ORIGIN = OS_SYSCALL_BEGIN, LENGTH = (OS_SYSCALL_END - OS_SYSCALL_BEGIN) + ocm : ORIGIN = OCM_FREE_START, LENGTH = OCM_FREE_LENGTH +} + +jiffies = jiffies_64 + 4; + +/* + * Fixed locations required by gdb coredumps. + * + * Note that the names are what gdb is expecting so renaming will break + * the toolchain. + */ +__ocm_begin = OCMSTART; +__ocm_limit = __ocm_begin + OCMSIZE; +__sdram_begin = SDRAMSTART; +__sdram_limit = __sdram_begin + CONFIG_MIN_RAMSIZE; +__filemedia_begin_addr = FLASHSTART; +__filemedia_end_addr = __filemedia_begin_addr + 0x00800000; + +/* + * For internal diagnostics + */ +__os_syscall_begin = OS_SYSCALL_BEGIN; +__os_syscall_end = OS_SYSCALL_END; + +SECTIONS { + + .fixed_text : { + _begin = .; + *(.skip_syscall) + *(.old_syscall_entry.text) + __fixed_text_end = .; + } > TEXT + . = _begin + SIZEOF(.fixed_text) ; + + /* + * System call text in lower ocm (fixed location, can never change) + */ + __syscall_text_load_begin = .; + __syscall_text_run_begin = OS_SYSCALL_BEGIN; + + .syscall_text __syscall_text_run_begin : AT(__syscall_text_load_begin) { + *(.syscall_entry.text) /* Must be at OS_SYSCALL_BEGIN 0x3ffc0040 */ + *(.kernel_unprotected) + . = ALIGN(4); + __syscall_text_run_end = .; + } > syscall /* .syscall_text */ + . = __syscall_text_load_begin + __syscall_text_run_end - __syscall_text_run_begin ; + __ocm_text_load_begin = .; + __ocm_text_run_begin = OCM_FREE_START ; + .ocm_text __ocm_text_run_begin : AT(__ocm_text_load_begin) { +#if OCM_TEXT_LENGTH + *(.ocm_text) + *(.sched.text) + *(.spinlock.text) +#include + . = ALIGN(4); +#endif + __ocm_text_run_end = .; + __data_begin = ALIGN(OCM_SECTOR_SIZE); + } > ocm /* .ocm_text */ + + .ocm_module_text __ocm_text_run_end (NOLOAD) : AT(__ocm_text_run_end) { + __ocm_inst_heap_begin = .; + /* Reserve the min requested */ + . += (CONFIG_OCM_MODULES_RESERVATION) * 1024; +#ifdef CONFIG_OCM_MODULES_MAY_CONSUME_REMAINING_CODESPACE + /* Round up to OCM sector size (we cannot use it for data) */ + . = ALIGN(OCM_SECTOR_SIZE); +#endif + __ocm_inst_heap_end = .; + /* update __data_begin */ + __data_begin = ALIGN(OCM_SECTOR_SIZE); + } > ocm /* .ocm_module_text */ + + . = __ocm_text_load_begin + __ocm_text_run_end - __ocm_text_run_begin ; + __ocm_text_load_end = .; + + __ocm_data_load_begin = .; + __ocm_data_run_begin = __data_begin ; +#if OCM_DATA_LENGTH + .ocm_data __ocm_data_run_begin : AT(__ocm_data_load_begin) { +#if defined(CONFIG_IRQSTACKS_USEOCM) + percpu_irq_stacks = .; + . += NR_CPUS * THREAD_SIZE; +#endif + *(.ocm_data) + . = ALIGN(4) ; + __ocm_data_run_end = .; + } > ocm + . = __ocm_data_load_begin + __ocm_data_run_end - __ocm_data_run_begin ; +#else + __ocm_data_run_end = __ocm_data_run_begin; +#endif + __ocm_data_load_end = .; + + __ocm_free_begin = __ocm_data_run_end; + __ocm_free_end = OCM_FREE_START + OCM_FREE_LENGTH; + + .text __ocm_data_load_end : AT(__ocm_data_load_end) { + . = ALIGN(4); + _stext = .; + _text = .; + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + *(.text.lock) + *(.text.__libgcc_udivmodsi) + *(.text.__libgcc_divmodsi) + *(.text.__libgcc_muldi3) + *(.text.__libgcc_udivmoddi) + *(.text.__libgcc_divmoddi) + *(.text.*) +#if OCM_TEXT_LENGTH == 0 + *(.ocm_text) + *(.sched.text) + *(.spinlock.text) +#endif + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + *(.rodata) *(.rodata.*) + *(__vermagic) /* Kernel version magic */ + *(__markers_strings) + *(.rodata1) + *(.rodata.str1.1) + *(__tracepoints_strings) + + /* PCI quirks */ + __start_pci_fixups_early = . ; + *(.pci_fixup_early) + __end_pci_fixups_early = . ; + __start_pci_fixups_header = . ; + *(.pci_fixup_header) + __end_pci_fixups_header = . ; + __start_pci_fixups_final = . ; + *(.pci_fixup_final) + __end_pci_fixups_final = . ; + __start_pci_fixups_enable = . ; + *(.pci_fixup_enable) + __end_pci_fixups_enable = . ; + __start_pci_fixups_resume = . ; + *(.pci_fixup_resume) + __end_pci_fixups_resume = . ; + __start_pci_fixups_resume_early = . ; + *(.pci_fixup_resume_early) + __end_pci_fixups_resume_early = . ; + __start_pci_fixups_suspend = . ; + *(.pci_fixup_suspend) + __end_pci_fixups_suspend = . ; + + __start_builtin_fw = . ; + *(.builtin_fw) + __end_builtin_fw = . ; + + + /* Kernel symbol table: Normal symbols */ + . = ALIGN(4); + __start___ksymtab = .; + *(__ksymtab) + __stop___ksymtab = .; + + /* Kernel symbol table: GPL-only symbols */ + __start___ksymtab_gpl = .; + *(__ksymtab_gpl) + __stop___ksymtab_gpl = .; + + /* Kernel symbol table: Normal unused symbols */ + __start___ksymtab_unused = .; + *(__ksymtab_unused) + __stop___ksymtab_unused = .; + + /* Kernel symbol table: GPL-only unused symbols */ + __start___ksymtab_unused_gpl = .; + *(__ksymtab_unused_gpl) + __stop___ksymtab_unused_gpl = .; + + /* Kernel symbol table: GPL-future symbols */ + __start___ksymtab_gpl_future = .; + *(__ksymtab_gpl_future) + __stop___ksymtab_gpl_future = .; + + /* Kernel symbol table: Normal symbols */ + __start___kcrctab = .; + *(__kcrctab) + __stop___kcrctab = .; + + /* Kernel symbol table: GPL-only symbols */ + __start___kcrctab_gpl = .; + *(__kcrctab_gpl) + __stop___kcrctab_gpl = .; + + /* Kernel symbol table: GPL-future symbols */ + __start___kcrctab_gpl_future = .; + *(__kcrctab_gpl_future) + __stop___kcrctab_gpl_future = .; + + /* Kernel symbol table: strings */ + *(__ksymtab_strings) + + /* Built-in module parameters */ + . = ALIGN(4) ; + __start___param = .; + *(__param) + __stop___param = .; + + . = ALIGN(4) ; + _etext = . ; + } > TEXT + + .data DATA_ADDR : { + . = ALIGN(4); + _sdata = . ; + DATA_DATA +#if OCM_DATA_LENGTH == 0 + *(.ocm_data) +#endif + . = ALIGN(8192) ; + _data_protection_end = .; + *(.data.init_task) + . = ALIGN(4); + _edata = . ; + } > DATA + + .init : { + . = ALIGN(4096); + __init_begin = .; + _sinittext = .; + INIT_TEXT + _einittext = .; + *(.init.rodata) + INIT_DATA + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + INITCALLS + __initcall_end = .; + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + ___security_initcall_start = .; + *(.security_initcall.init) + ___security_initcall_end = .; +#ifdef CONFIG_BLK_DEV_INITRD + . = ALIGN(4); + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; +#endif + . = ALIGN(4096); + __per_cpu_start = .; + *(.data.percpu) + *(.data.percpu.shared_aligned) + __per_cpu_end = .; + + . = ALIGN(4096); + __init_end = .; + } > INIT + + .eh_frame : + { + PROVIDE (___eh_frame_begin = .); + *(.eh_frame) + LONG (0); + PROVIDE (___eh_frame_end = .); + } > INIT + + /DISCARD/ : { + EXIT_TEXT + EXIT_DATA + *(.exitcall.exit) + } + + .bss : { + . = ALIGN(4); + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > BSS + + NOTES > BSS + +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/lib/Makefile b/target/linux/ubicom32/files/arch/ubicom32/lib/Makefile new file mode 100644 index 000000000..e7f41ccf3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/lib/Makefile @@ -0,0 +1,32 @@ +# +# arch/ubicom32/lib/Makefile +# +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# +# +# Makefile for m68knommu specific library files.. +# + +lib-y := checksum.o delay.o mem_ubicom32.o diff --git a/target/linux/ubicom32/files/arch/ubicom32/lib/checksum.c b/target/linux/ubicom32/files/arch/ubicom32/lib/checksum.c new file mode 100644 index 000000000..c93920f7c --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/lib/checksum.c @@ -0,0 +1,250 @@ +/* + * arch/ubicom32/lib/checksum.c + * Optimized checksum utilities for IP. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Andreas Schwab, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: + * Fixed some nasty bugs, causing some horrible crashes. + * A: At some points, the sum (%0) was used as + * length-counter instead of the length counter + * (%1). Thanks to Roman Hodek for pointing this out. + * B: GCC seems to mess up if one uses too many + * data-registers to hold input values and one tries to + * specify d0 and d1 as scratch registers. Letting gcc choose these + * registers itself solves the problem. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access kills, so most + of the assembly has to go. */ + +#include +#include + +static unsigned long do_csum(const unsigned char * buff, int len) +{ + int count; + unsigned long result = 0; + + /* + * The following optimized assembly code cannot handle data length less than 7 bytes! + */ + if (likely(len >= 7)) { + len -= (4 - (int)buff) & 3; + count = len >> 2; + asm ( + " sub.4 d15, #0, %2 \n\t" // set up for jump table + " and.4 d15, #(32-1), d15 \n\t" // d15 = (-m) & (32 - 1) + + " bfextu d14, %0, #2 \n\t" // test 2 LSB of buff + " jmpne.w.f 100f \n\t" + " add.4 %1, #0, %1 \n\t" // clear C + " moveai a3, #%%hi(1f) \n\t" // table jump + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.4 a3, (a3,d15) \n\t" + " calli a3, 0(a3) \n\t" + + "100: sub.4 %0, %0, d14 \n\t" + " sub.4 d14, #4, d14 \n\t" + " lsl.4 d14, d14, #3 \n\t" + " add.4 %1, #0, %1 \n\t" // clear C + " moveai a3, #%%hi(1f) \n\t" // table jump + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.4 a3, (a3,d15) \n\t" + " bfextu %1, (%0)4++, d14 \n\t" // read first partial word + " calli a3, 0(a3) \n\t" +#if 1 + "200: lsl.4 %3, %3, #3 \n\t" + " bfrvrs d15, (%0), #0 \n\t" // read last word (partial) + " bfextu d15, d15, %3 \n\t" + " bfrvrs d15, d15, #0 \n\t" + " add.4 %1, d15, %1 \n\t" + " addc %1, #0, %1 \n\t" // sample C again + " jmpt.w.t 2f \n\t" +#else + "200: move.1 d15, 0(%0) \n\t" + " lsl.4 d15, d15, #8 \n\t" + " add.4 %1, d15, %1 \n\t" + " addc %1, #0, %1 \n\t" // sample C again + " add.4 %3, #-1, %3 \n\t" + " jmpeq.w.t 2f \n\t" + + " move.1 d15, 1(%0) \n\t" + " add.4 %1, d15, %1 \n\t" + " addc %1, #0, %1 \n\t" // sample C again + " add.4 %3, #-1, %3 \n\t" + " jmpeq.w.t 2f \n\t" + + " move.1 d15, 2(%0) \n\t" + " lsl.4 d15, d15, #8 \n\t" + " add.4 %1, d15, %1 \n\t" + " addc %1, #0, %1 \n\t" // sample C again + " jmpt.w.t 2f \n\t" +#endif +#if defined(IP7000) || defined(IP7000_REV2) + "300: swapb.2 %1, %1 \n\t" +#else + "300: shmrg.2 %1, %1, %1 \n\t" + " lsr.4 %1, %1, #8 \n\t" + " bfextu %1, %1, #16 \n\t" +#endif + " jmpt.w.t 3f \n\t" + + "1: add.4 %1, (%0)4++, %1 \n\t" // first add without C + " .rept 31 \n\t" + " addc %1, (%0)4++, %1 \n\t" + " .endr \n\t" + " addc %1, #0, %1 \n\t" // sample C again + " add.4 %2, #-32, %2 \n\t" + " jmpgt.w.t 1b \n\t" + + " and.4 %3, #3, %3 \n\t" // check n + " jmpne.w.f 200b \n\t" + + "2: .rept 2 \n\t" + " lsr.4 d15, %1, #16 \n\t" + " bfextu %1, %1, #16 \n\t" + " add.4 %1, d15, %1 \n\t" + " .endr \n\t" + " btst d14, #3 \n\t" // start from odd address (<< 3)? + " jmpne.w.f 300b \n\t" + "3: \n\t" + + : "+a"(buff), "+d"(result), "+d"(count), "+d"(len) + : + : "d15", "d14", "a3", "cc" + ); + + return result; + } + + /* + * handle a few bytes and fold result into 16-bit + */ + while (len-- > 0) { + result += (*buff++ << 8); + if (len) { + result += *buff++; + len--; + } + } + asm ( + " .rept 2 \n\t" + " lsr.4 d15, %0, #16 \n\t" + " bfextu %0, %0, #16 \n\t" + " add.4 %0, d15, %0 \n\t" + " .endr \n\t" + : "+d" (result) + : + : "d15", "cc" + ); + + return result; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +__sum16 ip_fast_csum(const void *iph, unsigned int ihl) +{ + return (__force __sum16)~do_csum(iph,ihl*4); +} + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +__wsum csum_partial(const void *buff, int len, __wsum sum) +{ + unsigned int result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += (__force u32)sum; + if ((__force u32)sum > result) + result += 1; + return (__force __wsum)result; +} + +EXPORT_SYMBOL(csum_partial); + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +__sum16 ip_compute_csum(const void *buff, int len) +{ + return (__force __sum16)~do_csum(buff,len); +} + +/* + * copy from fs while checksumming, otherwise like csum_partial + */ + +__wsum +csum_partial_copy_from_user(const void __user *src, void *dst, + int len, __wsum sum, int *csum_err) +{ + if (csum_err) *csum_err = 0; + memcpy(dst, (__force const void *)src, len); + return csum_partial(dst, len, sum); +} + +/* + * copy from ds while checksumming, otherwise like csum_partial + */ + +__wsum +csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) +{ + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/lib/delay.c b/target/linux/ubicom32/files/arch/ubicom32/lib/delay.c new file mode 100644 index 000000000..d19f97f09 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/lib/delay.c @@ -0,0 +1,49 @@ +/* + * arch/ubicom32/lib/delay.c + * Ubicom32 implementation of udelay() + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include + +/* + * read_current_timer() + * Return the current value of sysval. + */ +int __devinit read_current_timer(unsigned long *timer_val) +{ + *timer_val = (long)(UBICOM32_IO_TIMER->sysval); + return 0; +} + + +void udelay(unsigned long usecs) +{ + _udelay(usecs); +} +EXPORT_SYMBOL(udelay); diff --git a/target/linux/ubicom32/files/arch/ubicom32/lib/mem_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/lib/mem_ubicom32.c new file mode 100644 index 000000000..d9c302ec6 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/lib/mem_ubicom32.c @@ -0,0 +1,343 @@ +/* + * arch/ubicom32/lib/mem_ubicom32.c + * String functions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include + +#define LIKELY likely +#define UNLIKELY unlikely + +typedef u32_t addr_t; + +/* + * memcpy() + */ +void *memcpy(void *dest, const void *src, size_t n) +{ + void *dest_ret = dest; + + if (LIKELY((((addr_t)dest ^ (addr_t)src) & 3) == 0) && LIKELY(n > 6)) { + size_t m; + n -= (4 - (addr_t)dest) & 0x03; + m = n >> 2; + asm volatile ( + " sub.4 d15, #0, %2 \n\t" // set up for jump table + " and.4 d15, #(32-1), d15 \n\t" // d15 = (-m) & (32 - 1) + " moveai a3, #%%hi(1f) \n\t" + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.4 a3, (a3,d15) \n\t" + + " bfextu d15, %0, #2 \n\t" // d15 = (dest & 3) + " jmpne.w.f 100f \n\t" + " calli a3, 0(a3) \n\t" // 4-byte alignment + + "100: cmpi d15, #2 \n\t" + " jmpne.s.f 101f \n\t" + " move.2 (%0)2++, (%1)2++ \n\t" + " calli a3, 0(a3) \n\t" // 2-byte alignment + + "101: move.1 (%0)1++, (%1)1++ \n\t" + " jmpgt.s.f 102f \n\t" // 3-byte alignment + " move.2 (%0)2++, (%1)2++ \n\t" // 1-byte alignment + "102: calli a3, 0(a3) \n\t" + + "200: cmpi %3, #2 \n\t" + " jmplt.s.f 201f \n\t" + " move.2 (%0)2++, (%1)2++ \n\t" + " jmpeq.s.t 2f \n\t" + "201: move.1 (%0)1++, (%1)1++ \n\t" + " jmpt.w.t 2f \n\t" + + "1: .rept 25 \n\t" + " movea (%0)4++, (%1)4++ \n\t" + " .endr \n\t" + " .rept 7 \n\t" + " move.4 (%0)4++, (%1)4++ \n\t" + " .endr \n\t" + " add.4 %2, #-32, %2 \n\t" + " jmpgt.w.f 1b \n\t" + + " and.4 %3, #3, %3 \n\t" // check n + " jmpne.w.f 200b \n\t" + "2: \n\t" + : "+a" (dest), "+a" (src), "+d" (m), "+d" (n) + : + : "d15", "a3", "memory", "cc" + ); + + return dest_ret; + } + + if (LIKELY((((addr_t)dest ^ (addr_t)src) & 1) == 0) && LIKELY(n > 2)) { + size_t m; + n -= (addr_t)dest & 0x01; + m = n >> 1; + asm volatile ( + " sub.4 d15, #0, %2 \n\t" // set up for jump table + " and.4 d15, #(32-1), d15 \n\t" // d15 = (-m) & (32 - 1) + " moveai a3, #%%hi(1f) \n\t" + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.4 a3, (a3,d15) \n\t" + + " btst %0, #0 \n\t" // check bit 0 + " jmpne.w.f 100f \n\t" + " calli a3, 0(a3) \n\t" // 4-byte alignment + + "100: move.1 (%0)1++, (%1)1++ \n\t" + " calli a3, 0(a3) \n\t" + + "200: move.1 (%0)1++, (%1)1++ \n\t" + " jmpt.w.t 2f \n\t" + + "1: .rept 32 \n\t" + " move.2 (%0)2++, (%1)2++ \n\t" + " .endr \n\t" + " add.4 %2, #-32, %2 \n\t" + " jmpgt.w.f 1b \n\t" + + " and.4 %3, #1, %3 \n\t" // check n + " jmpne.w.f 200b \n\t" + "2: \n\t" + + : "+a" (dest), "+a" (src), "+d" (m), "+d" (n) + : + : "d15", "a3", "memory", "cc" + ); + + return dest_ret; + } + + asm volatile ( + " sub.4 d15, #0, %2 \n\t" + " jmpeq.w.f 2f \n\t" + " and.4 d15, #(16-1), d15 \n\t" // d15 = (-n) & (16 - 1) + " moveai a3, #%%hi(1f) \n\t" + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.4 a3, (a3,d15) \n\t" + " calli a3, 0(a3) \n\t" + + "1: .rept 16 \n\t" + " move.1 (%0)1++, (%1)1++ \n\t" + " .endr \n\t" + " add.4 %2, #-16, %2 \n\t" + " jmpgt.w.f 1b \n\t" + "2: \n\t" + + : "+a" (dest), "+a" (src), "+d" (n) + : + : "d15", "a3", "memory", "cc" + ); + + return dest_ret; +} + +/* + * memset() + */ +void *memset(void *s, int c, size_t n) +{ + void *s_ret = s; + + if (LIKELY(n > 6)) { + size_t m; + n -= (4 - (addr_t)s) & 0x03; + m = n >> 2; + asm volatile ( + " sub.4 d15, #0, %2 \n\t" // set up for jump table + " and.4 d15, #(32-1), d15 \n\t" // d15 = (-m) & (32 - 1) + " shmrg.1 %1, %1, %1 \n\t" + " shmrg.2 %1, %1, %1 \n\t" // %1 = (c<<24)|(c<<16)|(c<<8)|c + " moveai a3, #%%hi(1f) \n\t" + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.4 a3, (a3,d15) \n\t" + + " bfextu d15, %0, #2 \n\t" // d15 = (s & 3) + " jmpne.w.f 100f \n\t" + " calli a3, 0(a3) \n\t" // 4-byte alignment + + "100: cmpi d15, #2 \n\t" + " jmpne.s.f 101f \n\t" + " move.2 (%0)2++, %1 \n\t" + " calli a3, 0(a3) \n\t" // 2-byte alignment + + "101: move.1 (%0)1++, %1 \n\t" + " jmpgt.s.f 102f \n\t" // 3-byte alignment + " move.2 (%0)2++, %1 \n\t" // 1-byte alignment + "102: calli a3, 0(a3) \n\t" + + "200: cmpi %3, #2 \n\t" + " jmplt.s.f 201f \n\t" + " move.2 (%0)2++, %1 \n\t" + " jmpeq.s.t 2f \n\t" + "201: move.1 (%0)1++, %1 \n\t" + " jmpt.w.t 2f \n\t" + + "1: .rept 25 \n\t" + " movea (%0)4++, %1 \n\t" + " .endr \n\t" + " .rept 7 \n\t" + " move.4 (%0)4++, %1 \n\t" + " .endr \n\t" + " add.4 %2, #-32, %2 \n\t" + " jmpgt.w.f 1b \n\t" + + " and.4 %3, #3, %3 \n\t" // test bit 1 of n + " jmpne.w.f 200b \n\t" + "2: \n\t" + + : "+a" (s), "+d" (c), "+d" (m), "+d" (n) + : + : "d15", "a3", "memory", "cc" + ); + + return s_ret; + } + + asm volatile ( + " sub.4 d15, #0, %2 \n\t" + " jmpeq.w.f 2f \n\t" + " and.4 d15, #(8-1), d15 \n\t" // d15 = (-%2) & (16 - 1) + " moveai a3, #%%hi(1f) \n\t" + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.4 a3, (a3,d15) \n\t" + " calli a3, 0(a3) \n\t" + + "1: .rept 8 \n\t" + " move.1 (%0)1++, %1 \n\t" + " .endr \n\t" + "2: \n\t" + + : "+a" (s), "+d" (c), "+d" (n) + : + : "d15", "a3", "memory", "cc" + ); + + return s_ret; +} + +void *memmove(void *dest, const void *src, size_t n) +{ + char *tmp; + const char *s; + + if (n == 0) + return dest; + + tmp = dest; + s = src; + + /* + * Will perform 16-bit move if possible + */ + if (likely((((u32)dest | (u32)src | n) & 1) == 0)) { + if (dest <= src) { + asm volatile ( + " sub.4 d15, #0, %2 \n\t" // set up for jump table + " and.4 d15, #(32-2), d15 \n\t" // d15 = (- count) & (32 - 2) + " moveai a3, #%%hi(1f) \n\t" + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.2 a3, (a3,d15) \n\t" + " calli a3, 0(a3) \n\t" + + "1: .rept 16 \n\t" + " move.2 (%0)2++, (%1)2++ \n\t" + " .endr \n\t" + " add.4 %2, #-32, %2 \n\t" + " jmpgt.w.f 1b \n\t" + + : "+a" (tmp), "+a" (s), "+d" (n) + : + : "d15", "a3", "memory", "cc" + ); + } else { + tmp += n; + s += n; + asm volatile ( + " sub.4 d15, #0, %2 \n\t" // set up for jump table + " and.4 d15, #(32-2), d15 \n\t" // d15 = (- count) & (32 - 2) + " moveai a3, #%%hi(1f) \n\t" + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.2 a3, (a3,d15) \n\t" + " calli a3, 0(a3) \n\t" + + "1: .rept 16 \n\t" + " move.2 -2(%0)++, -2(%1)++ \n\t" + " .endr \n\t" + " add.4 %2, #-32, %2 \n\t" + " jmpgt.w.f 1b \n\t" + + : "+a" (tmp), "+a" (s), "+d" (n) + : + : "d15", "a3", "memory", "cc" + ); + } + return dest; + } + + if (dest <= src) { + asm volatile ( + " sub.4 d15, #0, %2 \n\t" // set up for jump table + " and.4 d15, #(16-1), d15 \n\t" // d15 = (- count) & (16 - 1) + " moveai a3, #%%hi(1f) \n\t" + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.4 a3, (a3,d15) \n\t" + " calli a3, 0(a3) \n\t" + + "1: .rept 16 \n\t" + " move.1 (%0)1++, (%1)1++ \n\t" + " .endr \n\t" + " add.4 %2, #-16, %2 \n\t" + " jmpgt.w.f 1b \n\t" + : "+a" (tmp), "+a" (s), "+d" (n) + : + : "d15", "a3", "memory", "cc" + ); + } else { + tmp += n; + s += n; + asm volatile ( + " sub.4 d15, #0, %2 \n\t" // set up for jump table + " and.4 d15, #(16-1), d15 \n\t" // d15 = (- count) & (16 - 1) + " moveai a3, #%%hi(1f) \n\t" + " lea.1 a3, %%lo(1f)(a3) \n\t" + " lea.4 a3, (a3,d15) \n\t" + " calli a3, 0(a3) \n\t" + + "1: .rept 16 \n\t" + " move.1 -1(%0)++, -1(%1)++ \n\t" + " .endr \n\t" + " add.4 %2, #-16, %2 \n\t" + " jmpgt.w.f 1b \n\t" + : "+a" (tmp), "+a" (s), "+d" (n) + : + : "d15", "a3", "memory", "cc" + ); + } + return dest; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/Kconfig.switch b/target/linux/ubicom32/files/arch/ubicom32/mach-common/Kconfig.switch new file mode 100644 index 000000000..0303e1600 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/Kconfig.switch @@ -0,0 +1,12 @@ +menuconfig UBICOM_SWITCH + tristate "Switch devices" + help + This option provides Ethernet switch management options via proc fs + +if UBICOM_SWITCH +config UBICOM_SWITCH_BCM539X + tristate "Broadcom BCM539X series (SPI)" + depends on SPI_MASTER + help + Supports Broadcom BCM539X Gigabit Ethernet Switches over SPI +endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/Makefile b/target/linux/ubicom32/files/arch/ubicom32/mach-common/Makefile new file mode 100644 index 000000000..8c645aff6 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/Makefile @@ -0,0 +1,41 @@ +# +# arch/ubicom32/mach-common/Makefile +# Makefile for Ubicom32 generic drivers/code. +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# + +obj-y += cachectl.o common.o usb_tio.o usb.o ubi32-gpio.o board.o bootargs.o profile.o +obj-$(CONFIG_PCI) += pci.o io.o + +obj-$(CONFIG_FB_UBICOM32) += vdc_tio.o +obj-$(CONFIG_UBICOM_HID) += ubicom32hid.o +obj-$(CONFIG_UBICOM_INPUT) += ubicom32input.o +obj-$(CONFIG_UBICOM_INPUT_I2C) += ubicom32input_i2c.o +obj-$(CONFIG_UBICOM_SWITCH) += switch-core.o +obj-$(CONFIG_UBICOM_SWITCH_BCM539X) += switch-bcm539x.o +obj-$(CONFIG_UIO_UBICOM32RING) += ring_tio.o +obj-$(CONFIG_SND_UBI32) += audio.o +obj-$(CONFIG_UBICOM32_PLIO) += plio.o + diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/audio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/audio.c new file mode 100644 index 000000000..37db89093 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/audio.c @@ -0,0 +1,134 @@ +/* + * arch/ubicom32/mach-common/audio.c + * Generic initialization for Ubicom32 Audio + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include + +#include +#include +#include + +/* + * The number of audio devices currently allocated, used for .id + */ +static int __initdata audio_device_count; + +/* + * The maximum number of resources (cards) that the audio will have. + * Currently 3, a register space, and up to 2 interrupts. + */ +#define AUDIO_MAX_RESOURCES 3 + +/* + * audio_device_alloc + * Checks the device tree and allocates a platform_device if found + */ +struct platform_device * __init audio_device_alloc(const char *driver_name, + const char *node_name, const char *inst_name, int priv_bytes) +{ + struct platform_device *pdev; + struct resource *res; + struct audio_node *audio_node; + struct ubi32pcm_platform_data *pdata; + struct audio_dev_regs *adr; + int idx; + + /* + * Check the device tree for the audio node + */ + audio_node = (struct audio_node *)devtree_find_node(node_name); + if (!audio_node) { + printk(KERN_WARNING "audio device '%s' not found\n", node_name); + return NULL; + } + + if (audio_node->version != AUDIONODE_VERSION) { + printk(KERN_WARNING "audio node not compatible\n"); + return NULL; + } + + /* + * Find the instance in this node + */ + adr = audio_node->regs->adr; + for (idx = 0; idx < audio_node->regs->max_devs; idx++) { + if ((adr->version == AUDIO_DEV_REGS_VERSION) && + (strcmp(adr->name, inst_name) == 0)) { + break; + } + adr++; + } + if (idx == audio_node->regs->max_devs) { + printk(KERN_WARNING "audio inst '%s' not found in device '%s'\n", inst_name, node_name); + return NULL; + } + + /* + * Dynamically create the platform_device structure and resources + */ + pdev = kzalloc(sizeof(struct platform_device) + + sizeof(struct ubi32pcm_platform_data) + + priv_bytes , GFP_KERNEL); + if (!pdev) { + printk(KERN_WARNING "audio could not alloc pdev\n"); + return NULL; + } + + res = kzalloc(sizeof(struct resource) * AUDIO_MAX_RESOURCES, + GFP_KERNEL); + if (!res) { + kfree(pdev); + printk(KERN_WARNING "audio could not alloc res\n"); + return NULL; + } + + pdev->name = driver_name; + pdev->id = audio_device_count++; + pdev->resource = res; + + /* + * Fill in the resources and platform data from devtree information + */ + res[0].start = (u32_t)(audio_node->regs); + res[0].end = (u32_t)(audio_node->regs); + res[0].flags = IORESOURCE_MEM; + res[1 + AUDIO_TX_IRQ_RESOURCE].start = audio_node->dn.sendirq; + res[1 + AUDIO_TX_IRQ_RESOURCE].flags = IORESOURCE_IRQ; + res[1 + AUDIO_RX_IRQ_RESOURCE].start = audio_node->dn.recvirq; + res[1 + AUDIO_RX_IRQ_RESOURCE].flags = IORESOURCE_IRQ; + pdev->num_resources = 3; + + printk(KERN_INFO "Audio.%d '%s':'%s' found irq=%d/%d.%d regs=%p pdev=%p/%p\n", + pdev->id, node_name, inst_name, audio_node->dn.sendirq, + audio_node->dn.recvirq, idx, audio_node->regs, pdev, res); + pdata = (struct ubi32pcm_platform_data *)(pdev + 1); + pdev->dev.platform_data = pdata; + pdata->node_name = node_name; + pdata->inst_name = inst_name; + pdata->inst_num = idx; + if (priv_bytes) { + pdata->priv_data = pdata + 1; + } + + return pdev; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/board.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/board.c new file mode 100644 index 000000000..9634e3413 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/board.c @@ -0,0 +1,63 @@ +/* + * arch/ubicom32/mach-common/board.c + * Board init and support code. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include + +struct boardnode { + struct devtree_node dn; + const char *revision; +}; + +static const struct boardnode *bn; + +/* + * board_get_revision() + * Returns revision string of the board. + */ +const char *board_get_revision(void) +{ + if (!bn) { + return "NULL"; + } + + return bn->revision; +} + +/* + * board_init + */ +void __init board_init(void) +{ + bn = (struct boardnode *)devtree_find_node("board"); + if (!bn) { + printk(KERN_WARNING "board node not found\n"); + return; + } +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/bootargs.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/bootargs.c new file mode 100644 index 000000000..296715098 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/bootargs.c @@ -0,0 +1,63 @@ +/* + * arch/ubicom32/mach-common/bootargs.c + * Board init and support code. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include + +struct bootargsnode { + struct devtree_node dn; + const char cmdline[512]; +}; + +static const struct bootargsnode *ban; + +/* + * bootargs_get_cmdline() + * Returns kernel boot arguments set by the bootloader. + */ +const char *bootargs_get_cmdline(void) +{ + if (!ban) { + return ""; + } + + return ban->cmdline; +} + +/* + * bootargs_init + */ +void __init bootargs_init(void) +{ + ban = (struct bootargsnode *)devtree_find_node("bootargs"); + if (!ban) { + printk(KERN_WARNING "bootargs node not found\n"); + return; + } +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/cachectl.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/cachectl.c new file mode 100644 index 000000000..afb9dc4d4 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/cachectl.c @@ -0,0 +1,136 @@ +/* + * arch/ubicom32/mach-common/cachectl.c + * Architecture cache control support + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include + +/* + * The write queue flush procedure in mem_cache_control needs to make + * DCACHE_WRITE_QUEUE_LENGTH writes to DDR (not OCM). Here we reserve some + * memory for this operation. + * Allocate array of cache lines of least DCACHE_WRITE_QUEUE_LENGTH + 1 words in + * length rounded up to the nearest cache line. + */ +#define CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE \ + ALIGN(sizeof(int) * (DCACHE_WRITE_QUEUE_LENGTH + 1), CACHE_LINE_SIZE) + +static char cache_write_queue_flush_area[CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE] + __attribute__((aligned(CACHE_LINE_SIZE))); + +/* + * ONE_CCR_ADDR_OP is a helper macro that executes a single CCR operation. + */ +#define ONE_CCR_ADDR_OP(cc, op_addr, op) \ + do { \ + asm volatile ( \ + " btst "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)" \n\t" \ + " jmpne.f .-4 \n\t" \ + " move.4 "D(CCR_ADDR)"(%0), %1 \n\t" \ + " move.1 "D(CCR_CTRL+3)"(%0), %2 \n\t" \ + " bset "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)" \n\t" \ + " cycles 2 \n\t" \ + " btst "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_DONE)" \n\t" \ + " jmpeq.f .-4 \n\t" \ + : \ + : "a"(cc), "r"(op_addr), "r"(op & 0xff) \ + : "cc" \ + ); \ + } while (0) + +/* + * mem_cache_control() + * Special cache control operation + */ +void mem_cache_control(unsigned long cc, unsigned long begin_addr, + unsigned long end_addr, unsigned long op) +{ + unsigned long op_addr; + int dccr = cc == DCCR_BASE; + if (dccr && op == CCR_CTRL_FLUSH_ADDR) { + /* + * We ensure all previous writes have left the data cache write + * queue by sending DCACHE_WRITE_QUEUE_LENGTH writes (to + * different words) down the queue. If this is not done it's + * possible that the data we are trying to flush hasn't even + * entered the data cache. + * The +1 ensure that the final 'flush' is actually a flush. + */ + int *flush_area = (int *)cache_write_queue_flush_area; + asm volatile( + " .rept "D(DCACHE_WRITE_QUEUE_LENGTH + 1)" \n\t" + " move.4 (%0)4++, d0 \n\t" + " .endr \n\t" + : "+a"(flush_area) + ); + } + + if (dccr) + UBICOM32_LOCK(DCCR_LOCK_BIT); + else + UBICOM32_LOCK(ICCR_LOCK_BIT); + + /* + * Calculate the cache lines we need to operate on that include + * begin_addr though end_addr. + */ + begin_addr = begin_addr & ~(CACHE_LINE_SIZE - 1); + end_addr = (end_addr + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1); + op_addr = begin_addr; + + do { + ONE_CCR_ADDR_OP(cc, op_addr, op); + op_addr += CACHE_LINE_SIZE; + } while (likely(op_addr < end_addr)); + + if (dccr && op == CCR_CTRL_FLUSH_ADDR) { + /* + * It turns out that when flushing the data cache the last flush + * isn't actually complete at this point. This is because there + * is another write buffer on the DDR side of the cache that is + * arbitrated with the I-Cache. + * + * The only foolproof method that ensures that the last data + * cache flush *actually* completed is to do another flush on a + * dirty cache line. This flush will block until the DDR write + * buffer is empty. + * + * Rather than creating a another dirty cache line, we use the + * flush_area above as we know that it is dirty from previous + * writes. + */ + ONE_CCR_ADDR_OP(cc, cache_write_queue_flush_area, op); + } + + if (dccr) + UBICOM32_UNLOCK(DCCR_LOCK_BIT); + else + UBICOM32_UNLOCK(ICCR_LOCK_BIT); + +} +EXPORT_SYMBOL(mem_cache_control); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/common.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/common.c new file mode 100644 index 000000000..2f183bd10 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/common.c @@ -0,0 +1,64 @@ +/* + * arch/ubicom32/mach-common/common.c + * Common platform support. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Minimum CLK support */ + +struct clk *clk_get(struct device *dev, const char *id) +{ + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_put); + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/io.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/io.c new file mode 100644 index 000000000..3c55ba771 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/io.c @@ -0,0 +1,250 @@ +/* + * arch/ubicom32/mach-common/io.c + * PCI I/O memory read/write support functions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include + +#ifdef CONFIG_PCI +unsigned char ioread8(void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + return ubi32_pci_read_u8(addr); + else + return (unsigned char)(*(volatile unsigned char *)addr); +} +EXPORT_SYMBOL(ioread8); + +unsigned short ioread16(void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + return ubi32_pci_read_u16(addr); + else + return (unsigned short)(*(volatile unsigned short *)addr); +} +EXPORT_SYMBOL(ioread16); + +unsigned int ioread32(void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + return ubi32_pci_read_u32(addr); + else + return (unsigned int)(*(volatile unsigned int *)addr); +} +EXPORT_SYMBOL(ioread32); + +void iowrite32(unsigned int val, void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + ubi32_pci_write_u32(val, addr); + else + *(volatile unsigned int *)addr = val; +} +EXPORT_SYMBOL(iowrite32); + +void iowrite16(unsigned short val, void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + ubi32_pci_write_u16(val, addr); + else + *(volatile unsigned short *)addr = val; +} +EXPORT_SYMBOL(iowrite16); + +void iowrite8(unsigned char val, void __iomem *addr) +{ + if (IS_PCI_ADDRESS(addr)) + ubi32_pci_write_u8(val, addr); + else + *(volatile unsigned char *)addr = val; +} +EXPORT_SYMBOL(iowrite8); + +void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len) +{ + if (IS_PCI_ADDRESS(from)) { + if ((((u32_t)from & 0x3) == 0) && (((u32_t)to & 0x3) == 0)) { + while ((int)len >= 4) { + *(u32_t *)to = ubi32_pci_read_u32(from); + to += 4; + from += 4; + len -= 4; + } + } else if ((((u32_t)from & 0x1) == 0) && + (((u32_t)to & 0x1) == 0)) { + while ((int)len >= 2) { + *(u16_t *)to = ubi32_pci_read_u16(from); + to += 2; + from += 2; + len -= 2; + } + } + + while (len) { + *(u8_t *)to = ubi32_pci_read_u8(from); + to++; + from++; + len--; + } + } else + memcpy(to, (void *)from, len); +} +EXPORT_SYMBOL(memcpy_fromio); + +void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len) +{ + if (IS_PCI_ADDRESS(to)) { + if ((((u32_t)from & 0x3) == 0) && (((u32_t)to & 0x3) == 0)) { + while ((int)len >= 4) { + ubi32_pci_write_u32(*(u32_t *)from, to); + to += 4; + from += 4; + len -= 4; + } + } else if ((((u32_t)from & 0x1) == 0) && + (((u32_t)to & 0x1) == 0)) { + while ((int)len >= 2) { + ubi32_pci_write_u16(*(u16_t *)from, to); + to += 2; + from += 2; + len -= 2; + } + } + + while (len) { + ubi32_pci_write_u8(*(u8_t *)from, to); + from++; + to++; + len--; + } + } else + memcpy((void *)to, from, len); + +} +EXPORT_SYMBOL(memcpy_toio); + +void memset_io(volatile void __iomem *addr, int val, size_t len) +{ + if (IS_PCI_ADDRESS(addr)) { + while (len) { + ubi32_pci_write_u8((unsigned char)val, addr); + addr++; + len--; + } + } else + memset((void *)addr, val, len); + +} +EXPORT_SYMBOL(memset_io); + +void ioread8_rep(void __iomem *port, void *buf, unsigned long count) +{ + if (IS_PCI_ADDRESS(port)) { + while (count) { + *(u8_t *)buf = ioread8(port); + buf++; + count--; + } + } else { + insb((unsigned int)port, buf, count); + } + +} +EXPORT_SYMBOL(ioread8_rep); + +void ioread16_rep(void __iomem *port, void *buf, unsigned long count) +{ + if (IS_PCI_ADDRESS(port)) { + while (count) { + *(u16_t *)buf = ioread16(port); + buf += 2; + count--; + } + } else { + insw((unsigned int)port, buf, count); + } +} +EXPORT_SYMBOL(ioread16_rep); + +void ioread32_rep(void __iomem *port, void *buf, unsigned long count) +{ + if (IS_PCI_ADDRESS(port)) { + while (count) { + *(u32_t *)buf = ioread32(port); + buf += 4; + count--; + } + } else { + insl((unsigned int)port, buf, count); + } +} +EXPORT_SYMBOL(ioread32_rep); + +void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count) +{ + if (IS_PCI_ADDRESS(port)) { + while (count) { + iowrite8(*(u8_t *)buf, port); + buf++; + count--; + } + } else { + outsb((unsigned int)port, buf, count); + } + +} +EXPORT_SYMBOL(iowrite8_rep); + +void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count) +{ + if (IS_PCI_ADDRESS(port)) { + while (count) { + iowrite16(*(u16_t *)buf, port); + buf += 2; + count--; + } + } else { + outsw((unsigned int)port, buf, count); + } +} +EXPORT_SYMBOL(iowrite16_rep); + +void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count) +{ + if (IS_PCI_ADDRESS(port)) { + while (count) { + iowrite32(*(u32_t *)buf, port); + buf += 4; + count--; + } + } else { + outsl((unsigned int)port, buf, count); + } +} +EXPORT_SYMBOL(iowrite32_rep); + +#endif /* CONFIG_PCI */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/pci.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/pci.c new file mode 100644 index 000000000..a3a07121d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/pci.c @@ -0,0 +1,1157 @@ +/* + * arch/ubicom32/mach-common/pci.c + * PCI interface management. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int debug_pci = 1 ; + +/* #define PCI_USE_INTERNAL_LOCK 1 */ + +#ifdef PCI_USE_INTERNAL_LOCK +#define PCI_LOCK(lock, irqflag) pci_lock_acquire(irqflag) +#define PCI_UNLOCK(lock, irqflag) pci_lock_release(irqflag) +#elif defined(CONFIG_SMP) +static DEFINE_SPINLOCK(pci_master_lock); +#define PCI_LOCK(lock, irqflag) spin_lock_irqsave(lock, irqflag) +#define PCI_UNLOCK(lock, irqflag) spin_unlock_irqrestore(lock, irqflag) +#else +#define PCI_LOCK(lock, irqflag) local_irq_save(irqflag) +#define PCI_UNLOCK(lock, irqflag) local_irq_restore(irqflag) +#endif + +#define PCI_DEV0_IDSEL CONFIG_PCI_DEV0_IDSEL +#define PCI_DEV1_IDSEL CONFIG_PCI_DEV1_IDSEL + +/* + * PCI commands + */ +#define PCI_CMD_INT_ACK 0x00 /* not supported */ +#define PCI_CMD_SPECIAL 0x01 /* not supported */ +#define PCI_CMD_IO_READ 0x02 +#define PCI_CMD_IO_WRITE 0x03 +#define PCI_CMD_MEM_READ 0x06 +#define PCI_CMD_MEM_WRITE 0x07 +#define PCI_CMD_CFG_READ 0x0a +#define PCI_CMD_CFG_WRITE 0x0b +#define PCI_CMD_MEM_READ_MULT 0x0c /* not supported */ +#define PCI_CMD_DUAL_ADDR 0x0d /* not supported */ +#define PCI_CMD_MEM_READ_LINE 0x0e /* not supported */ +#define PCI_CMD_MEM_WRITE_INVAL 0x0f /* not supported */ +/* + * Status codes, returned by pci_read_u32() and pci_write_u32() + */ +#define PCI_RESP_IN_PROGRESS 0xff /* request still in queue */ +#define PCI_RESP_OK 0 +/* + * The following codes indicate that the request has completed + */ +#define PCI_RESP_NO_DEVSEL 1 /* timeout before target asserted + * DEVSEL! */ +#define PCI_RESP_LOST_DEVSEL 2 /* had DEVSEL, but went away before + * transfer completed! */ +#define PCI_RESP_BAD_TRDY 3 /* target asserted TRDY without + * DEVSEL! */ +#define PCI_RESP_NO_TRDY 4 /* timeout before target asserted + * TRDY! */ +#define PCI_RESP_BAD_STOP 5 /* target asserted STOP and TRDY + * without DEVSEL! */ +#define PCI_RESP_TARGET_ABORT 6 +#define PCI_RESP_TARGET_RETRY 7 +#define PCI_RESP_TARGET_DISCONNECT 8 +#define PCI_RESP_MISMATCH 9 /* data read back doesn't match data + * written - debug only, the core PCI + * routines never return this */ +#define PCI_RESP_DET_SERR 10 +#define PCI_RESP_DET_PERR 11 +#define PCI_RESP_MALFORMED_REQ 12 /* Could be due to misaligned + * requests or invalid address */ +#define PCI_RESP_NO_RESOURCE 13 /* Could be memory or other resourse + * like queue space */ +#define PCI_RESP_ERROR 14 /* All emcompassing error */ + +/* registers in PCI config space */ +#define PCI_DEVICE_VENDOR_ID_REG 0x00 +#define PCI_STATUS_COMMAND_REG 0x04 +#define PCI_CLASS_REVISION_REG 0x08 +#define PCI_BHLC_REG 0x0c /* BIST, Header type, Latency + * timer, Cache line size */ +#define PCI_BASE_ADDR_REG 0x10 +#define PCI_BASE_REG_COUNT 6 +#define CARDBUS_CIS_PTR_REG 0x28 +#define PCI_SUB_SYSTEM_ID_REG 0x2c +#define PCI_EXP_ROM_ADDR_REG 0x30 +#define PCI_CAP_PTR_REG 0x34 +#define PCI_LGPL_REG 0x3C /* max Latency, min Gnt, interrupt + * Pin, interrupt Line */ + +struct pci_master_request { + volatile u32_t pci_address; /* must be 4-byte aligned */ + volatile u32_t data; /* must be 4-byte aligned */ + volatile u8_t cmd; + volatile u8_t byte_valid; + volatile u8_t status; +}; + +struct pci_devnode { + struct devtree_node dn; + u32_t pci_idsel_0; + u32_t pci_idsel_1; + u32_t pci_cpu_address; + struct pci_master_request volatile *volatile req; +}; + +static struct pci_master_request req; /* globally used for faster master write + * (discarding result when possible) */ +static struct pci_devnode *pci_node; + +#if !defined(CONFIG_DEBUG_PCIMEASURE) +#define PCI_DECLARE_MEASUREMENT +#define PCI_MEASUREMENT_START() +#define PCI_MEASUREMENT_END(idx) +#else +#define PCI_DECLARE_MEASUREMENT \ + int __diff; \ + unsigned int __tstart; + +#define PCI_MEASUREMENT_START() \ + __tstart = UBICOM32_IO_TIMER->sysval; + +#define PCI_MEASUREMENT_END(idx) \ + __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \ + pci_measurement_update((idx), __diff); + +#define PCI_WEIGHT 32 + +struct pci_measurement { + volatile unsigned int min; + volatile unsigned int avg; + volatile unsigned int max; +}; + +enum pci_measurement_list { + PCI_MEASUREMENT_READ32, + PCI_MEASUREMENT_WRITE32, + PCI_MEASUREMENT_READ16, + PCI_MEASUREMENT_WRITE16, + PCI_MEASUREMENT_READ8, + PCI_MEASUREMENT_WRITE8, + PCI_MEASUREMENT_LAST, +}; + +static const char *pci_measurement_name_list[PCI_MEASUREMENT_LAST] = { + "READ32", + "WRITE32", + "READ16", + "WRITE16", + "READ8", + "WRITE8" +}; +static struct pci_measurement pci_measurements[PCI_MEASUREMENT_LAST]; + +/* + * pci_measurement_update() + * Update an entry in the measurement array for this idx. + */ +static void pci_measurement_update(int idx, int sample) +{ + struct pci_measurement *pm = &pci_measurements[idx]; + if ((pm->min == 0) || (pm->min > sample)) { + pm->min = sample; + } + if (pm->max < sample) { + pm->max = sample; + } + pm->avg = ((pm->avg * (PCI_WEIGHT - 1)) + sample) / PCI_WEIGHT; +} +#endif + +#if defined(PCI_USE_INTERNAL_LOCK) +/* + * pci_lock_release() + * Release the PCI lock. + */ +static void pci_lock_release(unsigned long irqflag) +{ + UBICOM32_UNLOCK(PCI_LOCK_BIT); +} + +/* + * pci_lock_acquire() + * Acquire the PCI lock, spin if not available. + */ +static void pci_lock_acquire(unsigned long irqflag) +{ + UBICOM32_LOCK(PCI_LOCK_BIT); +} +#endif + +/* + * pci_set_hrt_interrupt() + */ +static inline void pci_set_hrt_interrupt(struct pci_devnode *pci_node) +{ + ubicom32_set_interrupt(pci_node->dn.sendirq); +} + +/* + * pci_read_u32() + * Synchronously read 32 bits from PCI space. + */ +u8 pci_read_u32(u8 pci_cmd, u32 address, u32 *data) +{ + u8 status; + unsigned long irqflag; + + + /* + * Fill in the request. + */ + volatile struct pci_master_request lreq; + PCI_DECLARE_MEASUREMENT; + + lreq.pci_address = address; + lreq.cmd = pci_cmd; + lreq.byte_valid = 0xf; /* enable all bytes */ + + /* + * Wait for any previous request to complete and then make this request. + */ + PCI_MEASUREMENT_START(); + PCI_LOCK(&pci_master_lock, irqflag); + while (unlikely(pci_node->req == &req)) + ; + pci_node->req = &lreq; + pci_set_hrt_interrupt(pci_node); + PCI_UNLOCK(&pci_master_lock, irqflag); + + /* + * Wait for the result to show up. + */ + while (unlikely(pci_node->req == &lreq)) + ; + status = lreq.status; + if (likely(status == PCI_RESP_OK)) + *data = le32_to_cpu(lreq.data); + else + *data = 0; + PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ32); + return status; +} + +/* + * pci_write_u32() + * Asyncrhnously or synchronously write 32 bits to PCI master space. + */ +u8 pci_write_u32(u8 pci_cmd, u32 address, u32 data) +{ + unsigned long irqflag; + PCI_DECLARE_MEASUREMENT; + + /* + * Wait for any previous write or pending read to complete. + * + * We use a global data block because once we write the request + * we do not wait for it to complete before exiting. + */ + PCI_MEASUREMENT_START(); + PCI_LOCK(&pci_master_lock, irqflag); + while (unlikely(pci_node->req == &req)) + ; + req.pci_address = address; + req.data = cpu_to_le32(data); + req.cmd = pci_cmd; + req.byte_valid = 0xf; /* enable all bytes */ + pci_node->req = &req; + pci_set_hrt_interrupt(pci_node); + PCI_UNLOCK(&pci_master_lock, irqflag); + PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE32); + return PCI_RESP_OK; +} + +/* + * pci_read_u16() + * Synchronously read 16 bits from PCI space. + */ +u8 pci_read_u16(u8 pci_cmd, u32 address, u16 *data) +{ + u8 status; + unsigned long irqflag; + + /* + * Fill in the request. + */ + volatile struct pci_master_request lreq; + PCI_DECLARE_MEASUREMENT; + + lreq.pci_address = address & ~2; + lreq.cmd = pci_cmd; + lreq.byte_valid = (address & 2) ? 0xc : 0x3; + + /* + * Wait for any previous request to complete and then make this request. + */ + PCI_MEASUREMENT_START(); + PCI_LOCK(&pci_master_lock, irqflag); + while (unlikely(pci_node->req == &req)) + ; + pci_node->req = &lreq; + pci_set_hrt_interrupt(pci_node); + PCI_UNLOCK(&pci_master_lock, irqflag); + + /* + * Wait for the result to show up. + */ + while (unlikely(pci_node->req == &lreq)) + ; + status = lreq.status; + if (likely(status == PCI_RESP_OK)) { + lreq.data = le32_to_cpu(lreq.data); + *data = (u16)((address & 2) ? (lreq.data >> 16) : lreq.data); + } else + *data = 0; + PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ16); + return status; +} + +/* + * pci_write_u16() + * Asyncrhnously or synchronously write 16 bits to PCI master space. + */ +u8 pci_write_u16(u8 pci_cmd, u32 address, u16 data) +{ + unsigned long irqflag; + PCI_DECLARE_MEASUREMENT; + + /* + * Wait for any previous write or pending read to complete. + * + * We use a global data block because once we write the request + * we do not wait for it to complete before exiting. + */ + PCI_MEASUREMENT_START(); + PCI_LOCK(&pci_master_lock, irqflag); + while (unlikely(pci_node->req == &req)) + ; + req.pci_address = address & ~2; + req.data = (u32)data; + req.data = cpu_to_le32((address & 2) ? (req.data << 16) : req.data); + req.cmd = pci_cmd; + req.byte_valid = (address & 2) ? 0xc : 0x3; + pci_node->req = &req; + pci_set_hrt_interrupt(pci_node); + PCI_UNLOCK(&pci_master_lock, irqflag); + PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE16); + return PCI_RESP_OK; +} + +/* + * pci_read_u8() + * Synchronously read 8 bits from PCI space. + */ +u8 pci_read_u8(u8 pci_cmd, u32 address, u8 *data) +{ + u8 status; + unsigned long irqflag; + + /* + * Fill in the request. + */ + volatile struct pci_master_request lreq; + PCI_DECLARE_MEASUREMENT; + + lreq.pci_address = address & ~3; + lreq.cmd = pci_cmd; + lreq.byte_valid = 1 << (address & 0x3); + + /* + * Wait for any previous request to complete and then make this request. + */ + PCI_MEASUREMENT_START(); + PCI_LOCK(&pci_master_lock, irqflag); + while (unlikely(pci_node->req == &req)) + ; + pci_node->req = &lreq; + pci_set_hrt_interrupt(pci_node); + PCI_UNLOCK(&pci_master_lock, irqflag); + + /* + * Wait for the result to show up. + */ + while (unlikely(pci_node->req == &lreq)) + ; + status = lreq.status; + if (likely(status == PCI_RESP_OK)) { + *data = (u8)(lreq.data >> (24 - ((address & 0x3) << 3))); + } else + *data = 0; + PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ8); + return status; +} + +/* + * pci_write_u8() + * Asyncrhnously or synchronously write 8 bits to PCI master space. + */ +u8 pci_write_u8(u8 pci_cmd, u32 address, u8 data) +{ + unsigned long irqflag; + PCI_DECLARE_MEASUREMENT; + + /* + * Wait for any previous write or pending read to complete. + * + * We use a global data block because once we write the request + * we do not wait for it to complete before exiting. + */ + PCI_MEASUREMENT_START(); + PCI_LOCK(&pci_master_lock, irqflag); + while (unlikely(pci_node->req == &req)) + ; + req.pci_address = address & ~3; + req.data = ((u32)data << (24 - ((address & 0x3) << 3))); + req.cmd = pci_cmd; + req.byte_valid = 1 << (address & 0x3); + pci_node->req = &req; + pci_set_hrt_interrupt(pci_node); + PCI_UNLOCK(&pci_master_lock, irqflag); + PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE8); + return PCI_RESP_OK; +} + +unsigned int ubi32_pci_read_u32(const volatile void __iomem *addr) +{ + unsigned int data; + pci_read_u32(PCI_CMD_MEM_READ, (u32)addr, &data); + return data; +} +EXPORT_SYMBOL(ubi32_pci_read_u32); + +unsigned short ubi32_pci_read_u16(const volatile void __iomem *addr) +{ + unsigned short data; + pci_read_u16(PCI_CMD_MEM_READ, (u32)addr, &data); + return data; +} +EXPORT_SYMBOL(ubi32_pci_read_u16); + +unsigned char ubi32_pci_read_u8(const volatile void __iomem *addr) +{ + unsigned char data; + pci_read_u8(PCI_CMD_MEM_READ, (u32)addr, &data); + return data; +} +EXPORT_SYMBOL(ubi32_pci_read_u8); + +void ubi32_pci_write_u32(unsigned int val, const volatile void __iomem *addr) +{ + pci_write_u32(PCI_CMD_MEM_WRITE, (u32)addr, val); +} +EXPORT_SYMBOL(ubi32_pci_write_u32); + +void ubi32_pci_write_u16(unsigned short val, const volatile void __iomem *addr) +{ + pci_write_u16(PCI_CMD_MEM_WRITE, (u32)addr, val); +} +EXPORT_SYMBOL(ubi32_pci_write_u16); + +void ubi32_pci_write_u8(unsigned char val, const void volatile __iomem *addr) +{ + pci_write_u8(PCI_CMD_MEM_WRITE, (u32)addr, val); +} +EXPORT_SYMBOL(ubi32_pci_write_u8); + +#if defined(CONFIG_DEBUG_PCIMEASURE) +static unsigned int pci_cycles_to_nano(unsigned int cycles, unsigned int frequency) +{ + unsigned int nano = ((cycles * 1000) / (frequency / 1000000)); + return nano; +} + +/* + * pci_measurement_show() + * Print out the min, avg, max values for each PCI transaction type. + * + * By request, the max value is reset after each dump. + */ +static int pci_measurement_show(struct seq_file *p, void *v) +{ + unsigned int min, avg, max; + unsigned int freq = processor_frequency(); + int trans = *((loff_t *) v); + + if (trans == 0) { + seq_puts(p, "min\tavg\tmax\t(nano-seconds)\n"); + } + + if (trans >= PCI_MEASUREMENT_LAST) { + return 0; + } + + min = pci_cycles_to_nano(pci_measurements[trans].min, freq); + avg = pci_cycles_to_nano(pci_measurements[trans].avg, freq); + max = pci_cycles_to_nano(pci_measurements[trans].max, freq); + pci_measurements[trans].max = 0; + seq_printf(p, "%u\t%u\t%u\t%s\n", min, avg, max, pci_measurement_name_list[trans]); + return 0; +} + +static void *pci_measurement_start(struct seq_file *f, loff_t *pos) +{ + return (*pos < PCI_MEASUREMENT_LAST) ? pos : NULL; +} + +static void *pci_measurement_next(struct seq_file *f, void *v, loff_t *pos) +{ + (*pos)++; + if (*pos >= PCI_MEASUREMENT_LAST) + return NULL; + return pos; +} + +static void pci_measurement_stop(struct seq_file *f, void *v) +{ + /* Nothing to do */ +} + +static const struct seq_operations pci_measurement_seq_ops = { + .start = pci_measurement_start, + .next = pci_measurement_next, + .stop = pci_measurement_stop, + .show = pci_measurement_show, +}; + +static int pci_measurement_open(struct inode *inode, struct file *filp) +{ + return seq_open(filp, &pci_measurement_seq_ops); +} + +static const struct file_operations pci_measurement_fops = { + .open = pci_measurement_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init pci_measurement_init(void) +{ + proc_create("pci_measurements", 0, NULL, &pci_measurement_fops); + return 0; +} +module_init(pci_measurement_init); +#endif + +static int ubi32_pci_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *value) +{ + u8 cmd; + u32 addr; + u8 data8; + u16 data16; + + u8 slot = PCI_SLOT(devfn); + u8 fn = PCI_FUNC(devfn); + + if (slot > 1) { + return PCIBIOS_DEVICE_NOT_FOUND; + } else if (slot == 0) { + addr = PCI_DEV0_IDSEL + where; + } else { + addr = PCI_DEV1_IDSEL + where; + } + + addr += (fn << 8); + + cmd = PCI_CMD_CFG_READ; + if (size == 1) { + pci_read_u8(cmd, addr, &data8); + *value = (u32)data8; + } else if (size == 2) { + pci_read_u16(cmd, addr, &data16); + *value = (u32)data16; + } else { + pci_read_u32(cmd, addr, value); + } + + return PCIBIOS_SUCCESSFUL; +} + +static int ubi32_pci_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 value) +{ + u8 cmd; + u32 addr; + u8 slot = PCI_SLOT(devfn); + u8 fn = PCI_FUNC(devfn); + + if (slot > 1) { + return PCIBIOS_DEVICE_NOT_FOUND; + } else if (slot == 0) { + addr = PCI_DEV0_IDSEL + where; + } else { + addr = PCI_DEV1_IDSEL + where; + } + + addr += (fn << 8); + + cmd = PCI_CMD_CFG_WRITE; + if (size == 1) { + pci_write_u8(cmd, addr, (u8)value); + } else if (size == 2) { + pci_write_u16(cmd, addr, (u16)value); + } else { + pci_write_u32(cmd, addr, value); + } + + return PCIBIOS_SUCCESSFUL; +} + +int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size) +{ + return -EIO; +} +EXPORT_SYMBOL(pci_set_dma_max_seg_size); + +int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask) +{ + return -EIO; +} +EXPORT_SYMBOL(pci_set_dma_seg_boundary); + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + resource_size_t start = pci_resource_start(dev, bar); + resource_size_t len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) { + return NULL; + } + + if (maxlen && len > maxlen) { + len = maxlen; + } + + if (flags & IORESOURCE_IO) { + return ioport_map(start, len); + } + + if (flags & IORESOURCE_MEM) { + if (flags & IORESOURCE_CACHEABLE) { + return ioremap(start, len); + } + return ioremap_nocache(start, len); + } + return NULL; +} +EXPORT_SYMBOL(pci_iomap); + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + if ((unsigned long)addr >= VMALLOC_START && + (unsigned long)addr < VMALLOC_END) { + iounmap(addr); + } +} +EXPORT_SYMBOL(pci_iounmap); + +/* + * From arch/arm/kernel/bios32.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +static void __init pcibios_init_hw(struct hw_pci *hw) +{ + struct pci_sys_data *sys = NULL; + int ret; + int nr, busnr; + + for (nr = busnr = 0; nr < hw->nr_controllers; nr++) { + sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL); + if (!sys) + panic("PCI: unable to allocate sys data!"); + + sys->hw = hw; + sys->busnr = busnr; + sys->map_irq = hw->map_irq; + sys->resource[0] = &ioport_resource; + sys->resource[1] = &iomem_resource; + + ret = hw->setup(nr, sys); + + if (ret > 0) { + sys->bus = hw->scan(nr, sys); + + if (!sys->bus) + panic("PCI: unable to scan bus!"); + + busnr = sys->bus->subordinate + 1; + + list_add(&sys->node, &hw->buses); + } else { + kfree(sys); + if (ret < 0) + break; + } + } +} + +/* + * Swizzle the device pin each time we cross a bridge. + * This might update pin and returns the slot number. + */ +static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 *pin) +{ + struct pci_sys_data *sys = dev->sysdata; + int slot = 0, oldpin = *pin; + + if (sys->swizzle) + slot = sys->swizzle(dev, pin); + + if (debug_pci) + printk("PCI: %s swizzling pin %d => pin %d slot %d\n", + pci_name(dev), oldpin, *pin, slot); + return slot; +} + +/* + * Map a slot/pin to an IRQ. + */ +static int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + struct pci_sys_data *sys = dev->sysdata; + int irq = -1; + + if (sys->map_irq) + irq = sys->map_irq(dev, slot, pin); + + if (debug_pci) + printk("PCI: %s mapping slot %d pin %d => irq %d\n", + pci_name(dev), slot, pin, irq); + + return irq; +} + +void __init pci_common_init(struct hw_pci *hw) +{ + struct pci_sys_data *sys; + + INIT_LIST_HEAD(&hw->buses); + + if (hw->preinit) + hw->preinit(); + pcibios_init_hw(hw); + if (hw->postinit) + hw->postinit(); + + pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); + list_for_each_entry(sys, &hw->buses, node) { + struct pci_bus *bus = sys->bus; + /* + * Size the bridge windows. + */ + pci_bus_size_bridges(bus); + /* + * Assign resources. + */ + pci_bus_assign_resources(bus); + + /* + * Tell drivers about devices found. + */ + pci_bus_add_devices(bus); + } +} + +char * __init pcibios_setup(char *str) +{ + if (!strcmp(str, "debug")) { + debug_pci = 1; + return NULL; + } + return str; +} + +/* + * From arch/i386/kernel/pci-i386.c: + * + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might be mirrored at 0x0100-0x03ff.. + */ +void pcibios_align_resource(void *data, struct resource *res, + resource_size_t size, resource_size_t align) +{ + resource_size_t start = res->start; + + if (res->flags & IORESOURCE_IO && start & 0x300) + start = (start + 0x3ff) & ~0x3ff; + + res->start = (start + align - 1) & ~(align - 1); +} + + +void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) +{ + if (debug_pci) + printk("PCI: Assigning IRQ %02d to %s\n", irq, pci_name(dev)); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +/* + * If the bus contains any of these devices, then we must not turn on + * parity checking of any kind. Currently this is CyberPro 20x0 only. + */ +static inline int pdev_bad_for_parity(struct pci_dev *dev) +{ + return (dev->vendor == PCI_VENDOR_ID_INTERG && + (dev->device == PCI_DEVICE_ID_INTERG_2000 || + dev->device == PCI_DEVICE_ID_INTERG_2010)) || + (dev->vendor == PCI_VENDOR_ID_ITE && + dev->device == PCI_DEVICE_ID_ITE_8152); + +} + +/* + * Adjust the device resources from bus-centric to Linux-centric. + */ +static void __devinit +pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev) +{ + resource_size_t offset; + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (dev->resource[i].start == 0) + continue; + if (dev->resource[i].flags & IORESOURCE_MEM) + offset = root->mem_offset; + else + offset = root->io_offset; + + dev->resource[i].start += offset; + dev->resource[i].end += offset; + } +} + +static void __devinit +pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root) +{ + struct pci_dev *dev = bus->self; + int i; + + if (!dev) { + /* + * Assign root bus resources. + */ + for (i = 0; i < 3; i++) + bus->resource[i] = root->resource[i]; + } +} + +/* + * pcibios_fixup_bus - Called after each bus is probed, + * but before its children are examined. + */ +void pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_sys_data *root = bus->sysdata; + struct pci_dev *dev; + u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | + PCI_COMMAND_FAST_BACK; + + pbus_assign_bus_resources(bus, root); + + /* + * Walk the devices on this bus, working out what we can + * and can't support. + */ + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 status; + + pdev_fixup_device_resources(root, dev); + + pci_read_config_word(dev, PCI_STATUS, &status); + + /* + * If any device on this bus does not support fast back + * to back transfers, then the bus as a whole is not able + * to support them. Having fast back to back transfers + * on saves us one PCI cycle per transaction. + */ + if (!(status & PCI_STATUS_FAST_BACK)) + features &= ~PCI_COMMAND_FAST_BACK; + + if (pdev_bad_for_parity(dev)) + features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); + + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_PCI: + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status); + status |= PCI_BRIDGE_CTL_PARITY | + PCI_BRIDGE_CTL_MASTER_ABORT; + status &= ~(PCI_BRIDGE_CTL_BUS_RESET | + PCI_BRIDGE_CTL_FAST_BACK); + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status); + break; + + case PCI_CLASS_BRIDGE_CARDBUS: + pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL, + &status); + status |= PCI_CB_BRIDGE_CTL_PARITY | + PCI_CB_BRIDGE_CTL_MASTER_ABORT; + pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL, + status); + break; + } + } + + /* + * Now walk the devices again, this time setting them up. + */ + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 cmd; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= features; + pci_write_config_word(dev, PCI_COMMAND, cmd); + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + L1_CACHE_BYTES >> 2); + } + + /* + * Propagate the flags to the PCI bridge. + */ + if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + if (features & PCI_COMMAND_FAST_BACK) + bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK; + if (features & PCI_COMMAND_PARITY) + bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY; + } + + /* + * Report what we did for this bus + */ + printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n", + bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); +} +/* + * Convert from Linux-centric to bus-centric addresses for bridge devices. + */ +void +pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, + struct resource *res) +{ + struct pci_sys_data *root = dev->sysdata; + unsigned long offset = 0; + + if (res->flags & IORESOURCE_IO) + offset = root->io_offset; + if (res->flags & IORESOURCE_MEM) + offset = root->mem_offset; + + region->start = res->start - offset; + region->end = res->end - offset; +} + +void __devinit +pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, + struct pci_bus_region *region) +{ + struct pci_sys_data *root = dev->sysdata; + unsigned long offset = 0; + + if (res->flags & IORESOURCE_IO) + offset = root->io_offset; + if (res->flags & IORESOURCE_MEM) + offset = root->mem_offset; + + res->start = region->start + offset; + res->end = region->end + offset; +} + +#ifdef CONFIG_HOTPLUG +EXPORT_SYMBOL(pcibios_fixup_bus); +EXPORT_SYMBOL(pcibios_resource_to_bus); +EXPORT_SYMBOL(pcibios_bus_to_resource); +#endif + +/** + * pcibios_enable_device - Enable I/O and memory. + * @dev: PCI device to be enabled + */ +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1 << idx))) + continue; + + r = dev->resource + idx; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because" + " of resource collisions\n", pci_name(dev)); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + + /* + * Bridges (eg, cardbus bridges) need to be fully enabled + */ + if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) + cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + + if (cmd != old_cmd) { + printk("PCI: enabling device %s (%04x -> %04x)\n", + pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + + +struct pci_ops ubi32_pci_ops = { + .read = ubi32_pci_read_config, + .write = ubi32_pci_write_config, +}; + +static struct pci_bus *ubi32_pci_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(sys->busnr, &ubi32_pci_ops, sys); +} + +#define UBI32_PCI_MEM_BASE PCI_DEV_REG_BASE +#define UBI32_PCI_MEM_LEN 0x80000000 + +#define UBI32_PCI_IO_BASE 0x0 +#define UBI32_PCI_IO_END 0x0 + +static struct resource ubi32_pci_mem = { + .name = "PCI memory space", + .start = UBI32_PCI_MEM_BASE, + .end = UBI32_PCI_MEM_BASE + UBI32_PCI_MEM_LEN - 1, + .flags = IORESOURCE_MEM, +}; + +static struct resource ubi32_pci_io = { + .name = "PCI IO space", + .start = UBI32_PCI_IO_BASE, + .end = UBI32_PCI_IO_END, + .flags = IORESOURCE_IO, +}; + +static int __init ubi32_pci_setup(int nr, struct pci_sys_data *sys) +{ + if (nr > 0) + return 0; + + request_resource(&iomem_resource, &ubi32_pci_mem); + request_resource(&ioport_resource, &ubi32_pci_io); + + sys->resource[0] = &ubi32_pci_io; + sys->resource[1] = &ubi32_pci_mem; + sys->resource[2] = NULL; + + return 1; +} + +static void __init ubi32_pci_preinit(void) +{ +} + +static int __init ubi32_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return pci_node->dn.recvirq; +} + +struct hw_pci ubi32_pci __initdata = { + .nr_controllers = 1, + .preinit = ubi32_pci_preinit, + .setup = ubi32_pci_setup, + .scan = ubi32_pci_scan_bus, + .map_irq = ubi32_pci_map_irq, +}; + +static int __init ubi32_pci_init(void) +{ + pci_node = (struct pci_devnode *)devtree_find_node("pci"); + if (pci_node == NULL) { + printk(KERN_WARNING "PCI init failed\n"); + return -ENOSYS; + } + pci_common_init(&ubi32_pci); + return 0; +} + +subsys_initcall(ubi32_pci_init); + +/* + * workaround for dual PCI card interrupt + */ +#define PCI_COMMON_INT_BIT (1 << 19) +void ubi32_pci_int_wr(void) +{ + volatile unsigned int pci_int_line; + pci_int_line = UBICOM32_IO_PORT(RB)->gpio_in; + if (!(pci_int_line & PCI_COMMON_INT_BIT)) + { + ubicom32_set_interrupt(pci_node->dn.recvirq); + } +} +EXPORT_SYMBOL(ubi32_pci_int_wr); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/plio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/plio.c new file mode 100644 index 000000000..ac26a1e8d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/plio.c @@ -0,0 +1,92 @@ +/* + * plio.c + * PLIO state machine support functions + * + * Copyright © 2009 Ubicom Inc. . All rights reserved. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 2 of the License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include +#include +#include + +/* + * plio_reset + * Select and reset PLIO function + */ +static void plio_reset(const plio_fctl_t *plio_fctl) { + plio_io_function_t plio_function = { + .fn_sel = PLIO_FN, + .fn_reset = 1, + }; + + /* + * enable extension port + */ + PEXT_NBR->function = plio_function; + + /* + * program clock dividers + */ + PLIO_NBR->fctl2 = plio_fctl->fctl2; + + /* + * select plio function and assert function reset + */ + plio_function.br_thread = thread_get_self(); + plio_function.fn_reset = 1; + PLIO_NBR->function = plio_function; + + /* + * program plio controls + */ + PLIO_NBR->fctl0 = plio_fctl->fctl0; + PLIO_NBR->fctl1 = plio_fctl->fctl1; + + /* + * deassert function reset + */ + plio_function.fn_reset = 0; + PLIO_NBR->function = plio_function; +} + +/* + * plio_init + * configure and initialize PLIO. + */ +void plio_init(const plio_fctl_t *plio_fctl, const plio_config_t *plio_config, const plio_sram_t plio_sram_cfg[], int sram_cfg_size){ + /* + * first reset to start plio clock + */ + plio_reset(plio_fctl); + + udelay(1); + + /* + * configure pfsm + */ + PLIO_NBR->fctl0.pfsm_prog = 1; + memcpy(PLIO_BR->pfsm_sram, plio_sram_cfg, sram_cfg_size); + PLIO_NBR->fctl0.pfsm_prog = 0; + + /* + * program rest of plio + */ + memcpy(&PLIO_BR->config, plio_config, sizeof(plio_config_t)); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.c new file mode 100644 index 000000000..c95de6b17 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.c @@ -0,0 +1,549 @@ +/* + * arch/ubicom32/mach-common/profile.c + * Implementation for Ubicom32 Profiler + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include "profile.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * spacs for all memory blocks so we can hold locks for short time when walking tables + */ +#define PROFILE_NUM_MAPS 5000 +static struct profile_map profile_pm[PROFILE_NUM_MAPS]; + +static struct profilenode *node = NULL; +static int profile_first_packet = 1; + +static int profile_open(struct inode *inode, struct file *filp) +{ + if (!node) { + return -ENOENT; + } + node->busy = 1; + if (!node->enabled) { + node->enabled = 1; + node->busy = 0; + profile_first_packet = 1; + return 0; + } + node->busy = 0; + return -EBUSY; +} + +static int profile_sequence_num; + +/* + * make a packet full of sample data + */ +static int profile_make_data_packet(char *buf, int count) +{ + int samples; /* number of samples requested */ + int i; + struct profile_header ph; + char *ptr; + + if (count < sizeof(struct profile_header) + sizeof(struct profile_sample)) { + return -EINVAL; + } + + /* + * fill in the packet header + */ + memset(&ph, 0, sizeof(struct profile_header)); + ph.magic = PROF_MAGIC + PROFILE_VERSION; + ph.header_size = sizeof(struct profile_header); + ph.clocks = node->clocks; + for (i = 0; i < PROFILE_MAX_THREADS; ++i) { + ph.instruction_count[i] = node->inst_count[i]; + } + ph.profile_instructions = 0; + ph.enabled = node->enabled_threads; + ph.hrt = node->hrt; + ph.high = 0; + ph.profiler_thread = node->profiler_thread; + ph.clock_freq = node->clock_freq; + ph.seq_num = profile_sequence_num++; + ph.cpu_id = node->cpu_id; + ph.perf_counters[0] = node->stats[0]; + ph.perf_counters[1] = node->stats[1]; + ph.perf_counters[2] = node->stats[2]; + ph.perf_counters[3] = node->stats[3]; + ph.ddr_freq = node->ddr_freq; + + ptr = buf + sizeof(struct profile_header); + + samples = (count - sizeof(struct profile_header)) / sizeof(struct profile_sample); + for (i = 0; i < samples && node->count; ++i) { + if (copy_to_user(ptr, &node->samples[node->tail], sizeof(struct profile_sample)) != 0) { + return -EFAULT; + } + node->count--; + node->tail++; + if (node->tail >= node->max_samples) { + node->tail = 0; + } + ptr += sizeof(struct profile_sample); + } + ph.sample_count = i; + if (copy_to_user(buf, &ph, sizeof(struct profile_header)) != 0) { + return -EFAULT; + } + if (ph.sample_count == 0) + return 0; + else + return sizeof(struct profile_header) + ph.sample_count * sizeof(struct profile_sample); +} + +static void profile_get_memory_stats(unsigned int *total_free, unsigned int *max_free) +{ + struct list_head *p; + struct zone *zone; + unsigned int size; + + *total_free = 0; + *max_free = 0; + + /* + * get all the free regions. In each zone, the array of free_area lists contains the first page of each frame of size 1 << order + */ + for_each_zone(zone) { + unsigned long order, flags, i; + + if (!populated_zone(zone)) + continue; + + if (!is_normal(zone)) + continue; + + spin_lock_irqsave(&zone->lock, flags); + for_each_migratetype_order(order, i) { + size = ((1 << order) << PAGE_SHIFT) >> 10; + list_for_each(p, &(zone->free_area[order].free_list[i])) { + if (size > *max_free) { + *max_free = size; + } + *total_free += size; + } + } + spin_unlock_irqrestore(&zone->lock, flags); + } +} + +struct profile_counter_pkt profile_builtin_stats[] = +{ + { + "Free memory(KB)", 0 + }, + { + "Max free Block(KB)", 0 + } +}; + +/* + * make a packet full of performance counters + */ +static char prof_pkt[PROFILE_MAX_PACKET_SIZE]; +static int profile_make_stats_packet(char *buf, int count) +{ + char *ptr = prof_pkt; + struct profile_header_counters hdr; + int stat_count = 0; + int i; + unsigned int total_free, max_free; + int builtin_count = sizeof(profile_builtin_stats) / sizeof(struct profile_counter_pkt); + + if (count > PROFILE_MAX_PACKET_SIZE) { + count = PROFILE_MAX_PACKET_SIZE; + } + stat_count = (count - sizeof(struct profile_header_counters)) / sizeof (struct profile_counter_pkt); + stat_count -= builtin_count; + + if (stat_count <= 0) { + return 0; + } + + if (stat_count > node->num_counters) { + stat_count = node->num_counters; + } + + hdr.magic = PROF_MAGIC_COUNTERS; + hdr.ultra_sample_time = node->clocks; + hdr.ultra_count = stat_count; + hdr.linux_sample_time = UBICOM32_IO_TIMER->sysval; + hdr.linux_count = builtin_count; + memcpy(ptr, (void *)&hdr, sizeof(struct profile_header_counters)); + ptr += sizeof(struct profile_header_counters); + + + for (i = 0; i < stat_count; ++i) { + memcpy(ptr, (void *)(&(node->counters[i])), sizeof(struct profile_counter)); + ptr += sizeof(struct profile_counter); + } + + /* + * built in statistics + */ + profile_get_memory_stats(&total_free, &max_free); + profile_builtin_stats[0].value = total_free; + profile_builtin_stats[1].value = max_free; + memcpy(ptr, (void *)profile_builtin_stats, sizeof(profile_builtin_stats)); + ptr += sizeof(profile_builtin_stats); + + if (copy_to_user(buf, prof_pkt, ptr - prof_pkt) != 0) { + return -EFAULT; + } + return ptr - prof_pkt; +} + +/* + * return a udp packet ready to send to the profiler tool + * when there are no packets left to make, return 0 + */ +static int profile_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + int result = 0; + if (!node) { + return -ENOENT; + } + node->busy = 1; + if (!node->enabled) { + node->busy = 0; + return -EPERM; + } + if (!node->samples) { + node->busy = 0; + return -ENOMEM; + } + + if (profile_first_packet) { + result = profile_make_stats_packet(buf, count); + profile_first_packet = 0; + } + if (result == 0) { + result = profile_make_data_packet(buf, count); + if (result == 0) { + profile_first_packet = 1; + } + } + node->busy = 0; + return result; + +} + +static int profile_release(struct inode *inode, struct file *filp) +{ + if (!node) { + return -ENOENT; + } + node->busy = 1; + if (node->enabled) { + node->enabled = 0; + node->count = 0; + node->tail = node->head; + node->busy = 0; + return 0; + } + node->busy = 0; + profile_first_packet = 1; + return -EBADF; +} + +static const struct file_operations profile_fops = { + .open = profile_open, + .read = profile_read, + .release = profile_release, +}; + +static int page_aligned(void *x) +{ + return !((unsigned int)x & ((1 << PAGE_SHIFT) - 1)); +} + +static int profile_maps_open(struct inode *inode, struct file *filp) +{ + struct rb_node *rb; + int num = 0; + int slab_start; + struct vm_area_struct *vma; + int type = PROFILE_MAP_TYPE_UNKNOWN; + int flags, i; + struct list_head *p; + struct zone *zone; + + /* + * get the slab data (first so dups will show up as vmas) + */ + slab_start = num; + num += kmem_cache_block_info("size-512", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); + num += kmem_cache_block_info("size-1024", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); + num += kmem_cache_block_info("size-2048", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); + num += kmem_cache_block_info("size-4096", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); + num += kmem_cache_block_info("size-8192", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); + + for (i = slab_start; i < num; ++i) { + profile_pm[i].type_size |= PROFILE_MAP_TYPE_SMALL << PROFILE_MAP_TYPE_SHIFT; + } + + slab_start = num; + num += kmem_cache_block_info("dentry", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); + num += kmem_cache_block_info("inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); + num += kmem_cache_block_info("sysfs_dir_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); + num += kmem_cache_block_info("proc_inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); + + for (i = slab_start; i < num; ++i) { + profile_pm[i].type_size |= PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT; + } + + /* + * get all the vma regions (allocated by mmap, most likely + */ +#if 0 + down_read(&nommu_vma_sem); + for (rb = rb_first(&nommu_vma_tree); rb && num < PROFILE_NUM_MAPS; rb = rb_next(rb)) { + vma = rb_entry(rb, struct vm_area_struct, vm_rb); + profile_pm[num].start = (vma->vm_start - SDRAMSTART) >> PAGE_SHIFT; + profile_pm[num].type_size = (vma->vm_end - vma->vm_start + (1 << PAGE_SHIFT) - 1) >> PAGE_SHIFT; + flags = vma->vm_flags & 0xf; + if (flags == (VM_READ | VM_EXEC)) { + type = PROFILE_MAP_TYPE_TEXT; + } else if (flags == (VM_READ | VM_WRITE | VM_EXEC)) { + type = PROFILE_MAP_TYPE_STACK; + } else if (flags == (VM_READ | VM_WRITE)) { + type = PROFILE_MAP_TYPE_APP_DATA; + } + profile_pm[num].type_size |= type << PROFILE_MAP_TYPE_SHIFT; + num++; + } + up_read(&nommu_vma_sem); + if (rb) { + return -ENOMEM; + } +#endif + + /* + * get all the free regions. In each zone, the array of free_area lists contains the first page of each frame of size 1 << order + */ + for_each_zone(zone) { + unsigned long order, flags, i; + struct page *page; + + if (!populated_zone(zone)) + continue; + + if (!is_normal(zone)) + continue; + + spin_lock_irqsave(&zone->lock, flags); + for_each_migratetype_order(order, i) { + list_for_each(p, &(zone->free_area[order].free_list[i])) { + page = list_entry(p, struct page, lru); + profile_pm[num].start = ((page_to_phys(page) - SDRAMSTART) >> PAGE_SHIFT) - 0x40; + profile_pm[num].type_size = (PROFILE_MAP_TYPE_FREE << PROFILE_MAP_TYPE_SHIFT) | order; + num++; + if (num >= PROFILE_NUM_MAPS) { + spin_unlock_irqrestore(&zone->lock, flags); + return -ENOMEM; + } + } + } + spin_unlock_irqrestore(&zone->lock, flags); + } + + /* + * get the filesystem inodes + */ + list_for_each(p, &(super_blocks)) { + struct super_block *sb; + struct list_head *q; + if (num >= PROFILE_NUM_MAPS) + break; + sb = list_entry(p, struct super_block, s_list); + if (page_aligned(sb)) { + profile_pm[num].start = ((unsigned int)sb - SDRAMSTART) >> PAGE_SHIFT; + profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT); + num++; + } + list_for_each(q, &(sb->s_inodes)) { + struct inode *in; + if (num >= PROFILE_NUM_MAPS) + break; + in = list_entry(q, struct inode, i_sb_list); + if (page_aligned(in)) { + profile_pm[num].start = ((unsigned int)in - SDRAMSTART) >> PAGE_SHIFT; + profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT); + num++; + } + } + } + + /* + * get the buffer cache pages + */ + for (i = 0; i < num_physpages && num < PROFILE_NUM_MAPS; ++i) { + if ((mem_map + i)->flags & (1 << PG_lru)) { + int start = i; + while ((mem_map + i)->flags & (1 << PG_lru) && i < num_physpages) + i++; + profile_pm[num].start = start; + profile_pm[num].type_size = (i - start) | (PROFILE_MAP_TYPE_CACHE << PROFILE_MAP_TYPE_SHIFT); + num++; + } + } + + filp->private_data = (void *)num; + return 0; +} + +/* + * return one packet of map data, or 0 if all maps have been returned already + */ +static int profile_maps_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + struct profile_header_maps header; + char *p = buf + sizeof(header); + int total = (int)filp->private_data; + + header.count = (count - sizeof(header)) / sizeof(struct profile_map); + if (header.count > PROFILE_MAX_MAPS) { + header.count = PROFILE_MAX_MAPS;; + } + if (header.count > total - *f_pos) { + header.count = total - *f_pos; + } + + if (header.count == 0) { + return 0; + } + + header.magic = PROF_MAGIC_MAPS; + header.page_shift = PAGE_SHIFT; + + if (copy_to_user(buf, &header, sizeof(header)) != 0) { + return -EFAULT; + } + if (copy_to_user(p, (void *)&profile_pm[*f_pos], sizeof(struct profile_map) * header.count) != 0) { + return -EFAULT; + } + *f_pos += header.count; + + return sizeof(header) + sizeof(struct profile_map) * header.count; +} + +static int profile_maps_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static const struct file_operations profile_maps_fops = { + .open = profile_maps_open, + .read = profile_maps_read, + .release = profile_maps_release, +}; + +static int profile_rate_show(struct seq_file *m, void *v) +{ + if (node) { + seq_printf(m, "%d samples per second. %d virtual counters.\n", node->rate, node->num_counters); + } else { + seq_printf(m, "Profiler is not initialized.\n"); + } + return 0; +} + +static int profile_rate_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, profile_rate_show, NULL); +} + +static int profile_rate_write(struct file *filp, const char *buf, size_t len, loff_t *off) +{ + *off = 0; + return 0; +} + +static const struct file_operations profile_rate_fops = { + .open = profile_rate_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = profile_rate_write, +}; + +int ubi32_profile_init_module(void) +{ + struct proc_dir_entry *pdir; + + /* + * find the device + */ + node = (struct profilenode *)devtree_find_node("profiler"); + if (!node) { + printk(KERN_INFO "Profiler does not exist.\n"); + return -ENODEV; + } + + /* + * allocate the sample buffer + */ + node->max_samples = PROFILE_MAX_SAMPLES; + node->samples = kmalloc(node->max_samples * sizeof(struct profile_sample), GFP_KERNEL); + if (!node->samples) { + printk(KERN_INFO "Profiler sample buffer kmalloc failed.\n"); + return -ENOMEM; + } + + /* + * connect to the file system + */ + pdir = proc_mkdir("profile", NULL); + if (!pdir) { + return -ENOMEM; + } + if (!proc_create("data", 0, pdir, &profile_fops)) { + return -ENOMEM; + } + if (!proc_create("rate", 0, pdir, &profile_rate_fops)) { + return -ENOMEM; + } + if (!proc_create("maps", 0, pdir, &profile_maps_fops)) { + return -ENOMEM; + } + return 0; +} + + +module_init(ubi32_profile_init_module); + +MODULE_AUTHOR("David Fotland"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.h new file mode 100644 index 000000000..e6ff7d9fe --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.h @@ -0,0 +1,82 @@ +/* + * arch/ubicom32/mach-common/profile.h + * Private data for the profile module + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include "profpkt.h" + +#ifndef _PROFILE_H_ +#define _PROFILE_H_ + +#define PROFILE_MAX_THREADS 16 +#define PROFILE_MAX_SAMPLES 1024 + +struct profile_sample; +struct oprofile_sample; + +/* + * values chosen so all counter values fit in a single UDP packet + */ +#define PROFILE_NODE_MAX_COUNTERS 32 + +struct profile_counter { + char name[PROFILE_COUNTER_NAME_LENGTH]; + unsigned int value; +}; + +struct profilenode { + struct devtree_node dn; + volatile u32_t enabled; /* Is the profiler enabled to take samples? */ + volatile u32_t busy; /* set when the samples are being read by the driver */ + volatile u32_t rate; /* What is the sampling rate? */ + volatile u32_t enabled_threads; /* which threads were enabled at the last sample time */ + volatile u32_t hrt; /* HRT threads */ + volatile u32_t profiler_thread; /* thread running the profile sampler */ + volatile u32_t clocks; /* system clock timer at last sample */ + volatile u32_t clock_freq; /* clock frequency in Hz */ + volatile u32_t ddr_freq; /* memory frequency */ + volatile u32_t cpu_id; /* chip_id register */ + volatile u32_t inst_count[PROFILE_MAX_THREADS]; /* sampled instruction counts at most recent sample */ + volatile u32_t stats[4]; /* contents of the cache statistics counters */ + volatile u16_t head; /* sample taker puts samples here */ + volatile u16_t tail; /* packet filler takes samples here */ + volatile u16_t count; /* number of valid samples */ + volatile u16_t max_samples; /* how many samples can be in the samples array */ + struct profile_sample *samples; /* samples array allocated by the linux driver */ + volatile u32_t num_counters; /* how many registered performance counters */ + volatile struct profile_counter counters[PROFILE_NODE_MAX_COUNTERS]; + + /* unimplemented interface for future oprofile work */ + volatile u16_t oprofile_head; /* sample taker puts samples here */ + volatile u16_t oprofile_tail; /* packet filler takes samples here */ + volatile u16_t oprofile_count; /* how many oprofile sampels are are in use */ + volatile u16_t oprofile_max_samples; /* samples array size for oprofile samples */ + struct oprofile_sample *oprofile_samples; /* oprofile sample buffer */ +}; + +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/profpkt.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/profpkt.h new file mode 100644 index 000000000..37d9219a6 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/profpkt.h @@ -0,0 +1,158 @@ + +/* + * arch/ubicom32/mach-common/profpkt.c + * Ubicom32 Profiler packet formats for communication between the linux proc driver and the profiler display tool + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#define PROFILE_PORT 51080 +#define PROFILE_POSIX_NAME_LENGTH 32 + +/* + * profile UDP packet format for communicating between ip3k and host + * + * every packet starts with a header, followed by samples. + * samples are only taken for non-hrt threads that are + * active + */ +#define PROF_MAGIC 0x3ea0 +#define PROF_MAGIC_COUNTERS 0x9ea0 +#define PROF_MAGIC_MAPS 0xaea0 + +/* + * Versions (31 max): + * 1 to 4 were before 6.0 release, development versions + * 5 was forward compatible version, shipped with 6.0 and 6.1 + * 6 adds heap packets, and clock_freq to header, shipped with 6.2 + * 7 adds a sequence numbers to check for dropped packets, shipped with 6.3.5 + * 8 adds mqueue timing information, shipped with 6.3.5 + * 9 adds sdram heap size information, shipped with 6.4 + * 10 adds heapmem heap callers and long latency stack traces. shipped with 6.4 + * 11 adds support for Mars (IP5K). shipped with 6.10 + * 12 adds more support for Mars. Shipped with 7.0 + * 13 adds per sample latency measurement. Shipped with 7.2 + * 14 changes the heap format and adds a string packet. Shipped with 7.4 + * 15 adds dsr stats and posix. shipped with 7.6 + * 16 corrects maximum packet count for Ares. ships with 7.9 + * 17 adds a5 register value to sample + */ + +#define PROFILE_VERSION 17 +#define PROFILE_MAX_PACKET_SIZE 1440 + +#define PROFILE_MAX_THREADS 16 + +/* + * each packet starts with a profile_header, then sample_count samples + * samples are gprof samples of pc, the return address, condition codes, and + * active threads + */ +struct profile_header { + u16_t magic; /* magic number and version */ + u8_t header_size; /* number of bytes in profile header */ + u8_t sample_count; /* number of samples in the packet */ + u32_t clocks; /* clock counter value */ + u32_t instruction_count[PROFILE_MAX_THREADS]; + /* instructions executed per thread */ + u32_t profile_instructions; /* instructions executed by profiler mainline */ + u16_t enabled; /* which threads are enabled */ + u16_t hrt; /* which threads are hrt */ + u16_t high; /* which threads are high priority */ + u16_t profiler_thread; /* which thread runs the profiler */ + u32_t heap_free; /* current free on-cihp heap space in bytes */ + u32_t heap_low_water; /* on-chip heap low water mark */ + u32_t netpage_free; /* number of free on-chip net pages */ + u32_t netpage_low_water; /* low water mark on free on-chip netpages */ + u32_t min_sp[PROFILE_MAX_THREADS]; + /* stack pointer values per thread */ + u32_t clock_freq; /* clock frequency (Hz) of system being analyzed */ + u32_t seq_num; /* to detect dropped profiler packets */ + u32_t timing_sequence; /* sample number since boot */ + u32_t timing_interval; /* second per sample timing interval */ + u32_t timing_worst_time; /* duration of longest finction called, in core clocks */ + u32_t timing_function; /* address of longest function */ + u32_t timing_average; /* average time of all functions in last interval */ + u32_t timing_count; /* number of functions called in last interval */ + u32_t extheap_free; /* current free extmem heap space in bytes */ + u32_t extheap_low_water; /* extmem heap low water mark */ + u32_t cpu_id; /* CHIP_ID register contents */ + u32_t perf_counters[4]; /* contents of the CPU performance counters */ + u8_t perf_config[4]; /* what is being counted */ + u32_t ddr_freq; /* DDR clock frequency */ + u32_t extnetpage_free; /* number of free off chip net pages */ + u32_t extnetpage_low_water; /* low water mark on off-chip free netpages */ + u32_t dsr_max_latency; /* max time to process a dsr interrupt, in clocks, since last packet */ + u32_t dsr_ave_latency; /* average dsr latency over last DSR_STATS_RECENT_COUNT interrupts */ + u32_t dsr_count; /* number of dsr interrupts since last packet */ +}; + +struct profile_header_counters { + u16_t magic; + u16_t ultra_count; /* how many ultra counters follow this */ + u32_t ultra_sample_time; /* in chip clocks */ + u32_t linux_count; /* how many linux counters follow this */ + u32_t linux_sample_time; +}; + +/* + * values chosen so all counter values fit in a single 1400 byte UDP packet + */ +#define PROFILE_COUNTER_NAME_LENGTH 20 +#define PROFILE_MAX_COUNTERS ((PROFILE_MAX_PACKET_SIZE - sizeof(struct profile_header_counters)) / (PROFILE_COUNTER_NAME_LENGTH + 4)) + +struct profile_counter_pkt { + char name[PROFILE_COUNTER_NAME_LENGTH]; + unsigned int value; +}; + +/* + * send memory maps from linux to profiler tool + */ + +struct profile_header_maps { + u16_t magic; + u16_t count; + u32_t page_shift; +}; + +#define PROFILE_MAP_NUM_TYPES 32 + +/* types 0-15: size field is order. True size is 2^order */ +#define PROFILE_MAP_TYPE_UNKNOWN 0 +#define PROFILE_MAP_TYPE_FREE 1 +#define PROFILE_MAP_TYPE_SMALL 2 +#define PROFILE_MAP_TYPE_FS 3 +/* types 16-31: size field is pages. True size is (1 << PAGE_SHIFT) * size */ +#define PROFILE_MAP_SIZE_TYPE 16 +#define PROFILE_MAP_TYPE_TEXT 16 +#define PROFILE_MAP_TYPE_STACK 17 +#define PROFILE_MAP_TYPE_APP_DATA 18 +#define PROFILE_MAP_TYPE_CACHE 19 +#define PROFILE_MAP_RESERVED 24 + +#define PROFILE_MAP_TYPE_SHIFT 11 +#define PROFILE_MAP_SIZE_MASK 0x7ff + +struct profile_map { + u16_t start; /* start page number of segment, relative to start of DRAM */ + u16_t type_size; /* type (4 bits) of the segment and size in pages (12 bits) */ +}; + +#define PROFILE_MAX_MAPS (PROFILE_MAX_PACKET_SIZE - sizeof(struct profile_header_maps)) / sizeof(struct profile_map) diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c new file mode 100644 index 000000000..9d0f8cd2a --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c @@ -0,0 +1,123 @@ +/* + * arch/ubicom32/mach-common/ring_tio.c + * Generic initialization for UIO Ubicom32 Ring + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include + +#include +#include + +static const char *ring_tio_driver_name = "uio_ubicom32ring"; + +/* + * The number of ring_tio's currently allocated, used for .id + */ +static int __initdata ring_tio_count; + +/* + * The maximum number of resources that the ring_tio will have. + * Currently 3, a register space, and up to 2 interrupts. + */ +#define RING_TIO_MAX_RESOURCES 3 + +/* + * ring_tio_init + * Checks the device tree and instantiates the driver if found + */ +void __init ring_tio_init(const char *node_name) +{ + struct platform_device *pdev; + struct resource *res; + int resource_idx = 0; + struct ring_tio_node *ring_node; + + /* + * Check the device tree for the ring_tio + */ + ring_node = (struct ring_tio_node *)devtree_find_node(node_name); + if (!ring_node) { + printk(KERN_WARNING "Ring TIO '%s' not found\n", node_name); + return; + } + + if (ring_node->version != RING_TIO_NODE_VERSION) { + printk(KERN_WARNING "ring_tio not compatible\n"); + return; + } + + /* + * Dynamically create the platform_device structure and resources + */ + pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + if (!pdev) { + printk(KERN_WARNING "ring_tio could not alloc pdev\n"); + return; + } + + res = kzalloc(sizeof(struct resource) * RING_TIO_MAX_RESOURCES, + GFP_KERNEL); + if (!res) { + kfree(pdev); + printk(KERN_WARNING "ring_tio could not alloc res\n"); + return; + } + + pdev->name = ring_tio_driver_name; + pdev->id = ring_tio_count++; + pdev->resource = res; + + /* + * Fill in the resources and platform data from devtree information + */ + res[resource_idx].start = (u32_t)(ring_node->regs); + res[resource_idx].end = (u32_t)(ring_node->regs); + res[resource_idx].flags = IORESOURCE_MEM; + resource_idx++; + + if (ring_node->dn.sendirq != 0xFF) { + res[resource_idx].start = ring_node->dn.sendirq; + res[resource_idx].flags = IORESOURCE_IRQ; + resource_idx++; + } + + if (ring_node->dn.recvirq != 0xFF) { + res[resource_idx].start = ring_node->dn.recvirq; + res[resource_idx].flags = IORESOURCE_IRQ; + resource_idx++; + } + pdev->num_resources = resource_idx; + + printk(KERN_INFO "RingTIO.%d '%s' found irq=%d/%d regs=%p pdev=%p/%p\n", + ring_tio_count - 1, node_name, ring_node->dn.sendirq, + ring_node->dn.recvirq, ring_node->regs, pdev, res); + + /* + * Try to get the device registered + */ + pdev->dev.platform_data = (void *)node_name; + if (platform_device_register(pdev) < 0) { + printk(KERN_WARNING "Ring failed to register\n"); + kfree(pdev); + kfree(res); + } +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x-reg.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x-reg.h new file mode 100644 index 000000000..ca64eb146 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x-reg.h @@ -0,0 +1,221 @@ +/* + * arch/ubicom32/mach-common/switch-bcm539x-reg.h + * Broadcom switch definitions for Ubicom32 architecture. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +/* + * Broadcom 53xx RoboSwitch device driver. + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id$ + */ + +#ifndef _SWITCH_BCM539X_REG_H_ +#define _SWITCH_BCM539X_REG_H_ + +#define BCM539X_CMD_READ 0x60 +#define BCM539X_CMD_WRITE 0x61 + +#define BCM539X_GLOBAL_SPI_DATA0 0xf0 + +#define BCM539X_GLOBAL_SPI_STATUS 0xfe +#define BCM539X_GLOBAL_SPI_ST_SPIF (1<<7) +#define BCM539X_GLOBAL_SPI_ST_RACK (1<<5) + +#define BCM539X_GLOBAL_PAGE 0xff + +#define PAGE_PORT_TC 0x00 // Port Traffic Control Register + +#define PAGE_QOS_CTL 0x30 // QoS Global Control Register +#define PAGE_QOS_TAG 0x34 // Default IEEE 802.1Q TAG Register + +#define PAGE_MII_CTL_PORT0 0x10 // Internal PHY MII Register +#define PAGE_MII_CTL_PORT1 0x11 +#define PAGE_MII_CTL_PORT2 0x12 +#define PAGE_MII_CTL_PORT3 0x13 +#define PAGE_MII_CTL_PORT4 0x14 + +#define PAGE_STATUS 0x01 // Status Register Page +#define PAGE_RATE_CONTROL 0x41 // Broadcast Storm Suppression Register + +#define REG_GRATE_CONTROL 0x00 + +#define REG_LED_POWER 0x12 + +// Ingress Rate Control +#define REG_IRATE_CONTROLP0 0x10 +#define REG_IRATE_CONTROLP1 0x14 +#define REG_IRATE_CONTROLP2 0x18 +#define REG_IRATE_CONTROLP3 0x1C +#define REG_IRATE_CONTROLP4 0x20 +#define REG_IRATE_CONTROLP7 0x2C +#define REG_IRATE_CONTROLPI 0x30 + +// Egress Rate Control +#define REG_ERATE_CONTROLP0 0x80 +#define REG_ERATE_CONTROLP1 0x82 +#define REG_ERATE_CONTROLP2 0x84 +#define REG_ERATE_CONTROLP3 0x86 +#define REG_ERATE_CONTROLP4 0x88 +#define REG_ERATE_CONTROLP5 0x8A +#define REG_ERATE_CONTROLP6 0x8C +#define REG_ERATE_CONTROLP7 0x8E +#define REG_ERATE_CONTROLPI 0x90 + +#define REG_LINK_STATUS 0x00 + +#define REG_TC_PORT0 0x00 +#define REG_TC_PORT1 0x01 +#define REG_TC_PORT2 0x02 +#define REG_TC_PORT3 0x03 +#define REG_TC_PORT4 0x04 +#define REG_TC_PORT5 0x05 + +#define REG_SPEED_CTL 0x00 +#define REG_SPEED_ADV100 0x08 +#define REG_SPEED_ADV1000 0x12 + +#define REG_QOS_EN 0x00 +#define REG_QOS_TAG_PORT1 0x12 // Default IEEE 802.1Q TAG, PORT 1 +#define REG_QOS_TAG_PORT2 0x14 // Default IEEE 802.1Q TAG, PORT 2 +#define REG_QOS_TAG_PORT3 0x16 // Default IEEE 802.1Q TAG, PORT 3 +#define REG_QOS_TAG_PORT4 0x18 // Default IEEE 802.1Q TAG, PORT 4 +#define REG_QOS_PID_PORT1 0x52 // Ingress Port Priority ID MAP, PORT 1 +#define REG_QOS_PID_PORT2 0x54 // Ingress Port Priority ID MAP, PORT 2 +#define REG_QOS_PID_PORT3 0x56 // Ingress Port Priority ID MAP, PORT 3 +#define REG_QOS_PID_PORT4 0x58 // Ingress Port Priority ID MAP, PORT 4 +#define REG_QOS_TXQ_CTL 0x80 // Tx Queue Control Register +#define REG_QOS_TXQ_WHTQ0 0x81 // Tx Queue Weight Register Queue 0 +#define REG_QOS_TXQ_WHTQ1 0x82 // Tx Queue Weight Register Queue 1 +#define REG_QOS_TXQ_WHTQ2 0x83 // Tx Queue Weight Register Queue 2 +#define REG_QOS_TXQ_WHTQ3 0x84 // Tx Queue Weight Register Queue 3 + +#define REG_CTRL_PPSEL 0x24 /* 5397: Protected port select register */ + +#define RATE_CONTROL_ENABLED (1 << 22) +#define RATE_CONTROL_BSIZE ((1 << 10) | (1 << 9) | (1 << 8)) + +#define RATE_CONTROL_HIGH ((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4)) +#define RATE_CONTROL_HIGH_N ~((1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)) + +#define RATE_CONTROL_MEDIUM ((1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)) +#define RATE_CONTROL_MEDIUM_N ~((1 << 7)) + +#define RATE_CONTROL_NORMAL ((1 << 5) | (1 << 2) | (1 << 0)) +#define RATE_CONTROL_NORMAL_N ~((1 << 7) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1)) + +#define RATE_CONTROL_LOW ((1 << 4) | (1 << 3) | (1 << 0)) +#define RATE_CONTROL_LOW_N ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2) | (1 << 1)) + +// --- Gemtek, Configure the switch to support Ethernet Port QoS + +/* MII access registers */ +#define PSEUDO_PHYAD 0x1E /* MII Pseudo PHY address */ +#define REG_MII_PAGE 0x10 /* MII Page register */ +#define REG_MII_ADDR 0x11 /* MII Address register */ +#define REG_MII_DATA0 0x18 /* MII Data register 0 */ +#define REG_MII_DATA1 0x19 /* MII Data register 1 */ +#define REG_MII_DATA2 0x1a /* MII Data register 2 */ +#define REG_MII_DATA3 0x1b /* MII Data register 3 */ + +/* Page numbers */ +#define PAGE_CTRL 0x00 /* Control page */ +#define PAGE_MMR 0x02 /* 5397 Management/Mirroring page */ +#define PAGE_VTBL 0x05 /* ARL/VLAN Table access page */ +#define PAGE_VLAN 0x34 /* VLAN page */ + +/* Control page registers */ +#define REG_CTRL_PORT0 0x00 /* Port 0 traffic control register */ +#define REG_CTRL_PORT1 0x01 /* Port 1 traffic control register */ +#define REG_CTRL_PORT2 0x02 /* Port 2 traffic control register */ +#define REG_CTRL_PORT3 0x03 /* Port 3 traffic control register */ +#define REG_CTRL_PORT4 0x04 /* Port 4 traffic control register */ +#define REG_CTRL_PORT5 0x05 /* Port 5 traffic control register */ +#define REG_CTRL_PORT6 0x06 /* Port 6 traffic control register */ +#define REG_CTRL_PORT7 0x07 /* Port 7 traffic control register */ +#define REG_CTRL_MODE 0x0B /* Switch Mode register */ +#define REG_CTRL_MIIPO 0x0E /* 5325: MII Port Override register */ +#define REG_CTRL_SRST 0x79 /* Software reset control register */ + +#define REG_DEVICE_ID 0x30 /* 539x Device id: */ +#define DEVID5395 0x95 /* 5395 */ +#define DEVID5397 0x97 /* 5397 */ +#define DEVID5398 0x98 /* 5398 */ +#define REG_REVISION_ID 0x40 /* 539x Revision id: */ + +/* VLAN page registers */ +#define REG_VLAN_CTRL0 0x00 /* VLAN Control 0 register */ +#define REG_VLAN_CTRL1 0x01 /* VLAN Control 1 register */ +#define REG_VLAN_CTRL2 0x02 /* VLAN Control 2 register */ +#define REG_VLAN_CTRL3 0x03 /* VLAN Control 3 register */ +#define REG_VLAN_CTRL4 0x04 /* VLAN Control 4 register */ +#define REG_VLAN_CTRL5 0x05 /* VLAN Control 5 register */ +#define REG_VLAN_ACCESS 0x06 /* VLAN Table Access register */ +#define REG_VLAN_WRITE 0x08 /* VLAN Write register */ +#define REG_VLAN_READ 0x0C /* VLAN Read register */ +#define REG_VLAN_PTAG0 0x10 /* VLAN Default Port Tag register - port 0 */ +#define REG_VLAN_PTAG1 0x12 /* VLAN Default Port Tag register - port 1 */ +#define REG_VLAN_PTAG2 0x14 /* VLAN Default Port Tag register - port 2 */ +#define REG_VLAN_PTAG3 0x16 /* VLAN Default Port Tag register - port 3 */ +#define REG_VLAN_PTAG4 0x18 /* VLAN Default Port Tag register - port 4 */ +#define REG_VLAN_PTAG5 0x1a /* VLAN Default Port Tag register - port 5 */ +#define REG_VLAN_PTAG6 0x1c /* VLAN Default Port Tag register - port 6 */ +#define REG_VLAN_PTAG7 0x1e /* VLAN Default Port Tag register - port 7 */ +#define REG_VLAN_PTAG8 0x20 /* 539x: VLAN Default Port Tag register - IMP port */ +#define REG_VLAN_PMAP 0x20 /* 5325: VLAN Priority Re-map register */ + +/* ARL/VLAN Table Access page registers */ +#define REG_VTBL_CTRL 0x00 /* ARL Read/Write Control */ +#define REG_VTBL_MINDX 0x02 /* MAC Address Index */ +#define REG_VTBL_VINDX 0x08 /* VID Table Index */ +#define REG_VTBL_ARL_E0 0x10 /* ARL Entry 0 */ +#define REG_VTBL_ARL_E1 0x18 /* ARL Entry 1 */ +#define REG_VTBL_DAT_E0 0x18 /* ARL Table Data Entry 0 */ +#define REG_VTBL_SCTRL 0x20 /* ARL Search Control */ +#define REG_VTBL_SADDR 0x22 /* ARL Search Address */ +#define REG_VTBL_SRES 0x24 /* ARL Search Result */ +#define REG_VTBL_SREXT 0x2c /* ARL Search Result */ +#define REG_VTBL_VID_E0 0x30 /* VID Entry 0 */ +#define REG_VTBL_VID_E1 0x32 /* VID Entry 1 */ +#define REG_VTBL_PREG 0xFF /* Page Register */ +#define REG_VTBL_ACCESS 0x60 /* VLAN table access register */ +#define REG_VTBL_INDX 0x61 /* VLAN table address index register */ +#define REG_VTBL_ENTRY 0x63 /* VLAN table entry register */ +#define REG_VTBL_ACCESS_5395 0x80 /* VLAN table access register */ +#define REG_VTBL_INDX_5395 0x81 /* VLAN table address index register */ +#define REG_VTBL_ENTRY_5395 0x83 /* VLAN table entry register */ + +/* SPI registers */ +#define REG_SPI_PAGE 0xff /* SPI Page register */ + +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x.c new file mode 100644 index 000000000..d9eca381a --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x.c @@ -0,0 +1,1195 @@ +/* + * arch/ubicom32/mach-common/switch-bcm539x.c + * BCM539X switch driver, SPI mode + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include + +#include +#include +#include "switch-core.h" +#include "switch-bcm539x-reg.h" + +#define DRIVER_NAME "bcm539x-spi" +#define DRIVER_VERSION "1.0" + +#undef BCM539X_DEBUG +#define BCM539X_SPI_RETRIES 100 + +struct bcm539x_data { + struct switch_device *switch_dev; + + /* + * Our private data + */ + struct spi_device *spi; + struct switch_core_platform_data *pdata; + + /* + * Last page we accessed + */ + u8_t last_page; + + /* + * 539x Device ID + */ + u8_t device_id; +}; + +/* + * bcm539x_wait_status + * Waits for the specified bit in the status register to be set/cleared. + */ +static int bcm539x_wait_status(struct bcm539x_data *bd, u8_t mask, int set) +{ + u8_t txbuf[2]; + u8_t rxbuf; + int i; + int ret; + + txbuf[0] = BCM539X_CMD_READ; + txbuf[1] = BCM539X_GLOBAL_SPI_STATUS; + for (i = 0; i < BCM539X_SPI_RETRIES; i++) { + ret = spi_write_then_read(bd->spi, txbuf, 2, &rxbuf, 1); + rxbuf &= mask; + if ((set && rxbuf) || (!set && !rxbuf)) { + return 0; + } + udelay(1); + } + + return -EIO; +} + +/* + * bcm539x_set_page + * Sets the register page for access (only if necessary) + */ +static int bcm539x_set_page(struct bcm539x_data *bd, u8_t page) +{ + u8_t txbuf[3]; + + if (page == bd->last_page) { + return 0; + } + + bd->last_page = page; + + txbuf[0] = BCM539X_CMD_WRITE; + txbuf[1] = BCM539X_GLOBAL_PAGE; + txbuf[2] = page; + + return spi_write(bd->spi, txbuf, 3); +} + +/* + * bcm539x_write_bytes + * Writes a number of bytes to a given page and register + */ +static int bcm539x_write_bytes(struct bcm539x_data *bd, u8_t page, + u8_t reg, void *buf, u8_t len) +{ + int ret; + u8_t *txbuf; + + txbuf = kmalloc(2 + len, GFP_KERNEL); + if (!txbuf) { + return -ENOMEM; + } + + /* + * Make sure the chip has finished processing our previous request + */ + ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_SPIF, 0); + if (ret) { + goto done; + } + + /* + * Set the page + */ + ret = bcm539x_set_page(bd, page); + if (ret) { + goto done; + } + + /* + * Read the data + */ + txbuf[0] = BCM539X_CMD_WRITE; + txbuf[1] = reg; + memcpy(&txbuf[2], buf, len); + +#ifdef BCM539X_DEBUG + { + int i; + printk("write page %02x reg %02x len=%d buf=", page, reg, len); + for (i = 0; i < len + 2; i++) { + printk("%02x ", txbuf[i]); + } + printk("\n"); + } +#endif + + ret = spi_write(bd->spi, txbuf, 2 + len); + +done: + kfree(txbuf); + return ret; +} + +/* + * bcm539x_write_32 + * Writes 32 bits of data to the given page and register + */ +static inline int bcm539x_write_32(struct bcm539x_data *bd, u8_t page, + u8_t reg, u32_t data) +{ + data = cpu_to_le32(data); + return bcm539x_write_bytes(bd, page, reg, &data, 4); +} + +/* + * bcm539x_write_16 + * Writes 16 bits of data to the given page and register + */ +static inline int bcm539x_write_16(struct bcm539x_data *bd, u8_t page, + u8_t reg, u16_t data) +{ + data = cpu_to_le16(data); + return bcm539x_write_bytes(bd, page, reg, &data, 2); +} + +/* + * bcm539x_write_8 + * Writes 8 bits of data to the given page and register + */ +static inline int bcm539x_write_8(struct bcm539x_data *bd, u8_t page, + u8_t reg, u8_t data) +{ + return bcm539x_write_bytes(bd, page, reg, &data, 1); +} + +/* + * bcm539x_read_bytes + * Reads a number of bytes from a given page and register + */ +static int bcm539x_read_bytes(struct bcm539x_data *bd, u8_t page, + u8_t reg, void *buf, u8_t len) +{ + u8_t txbuf[2]; + int ret; + + /* + * (1) Make sure the chip has finished processing our previous request + */ + ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_SPIF, 0); + if (ret) { + return ret; + } + + /* + * (2) Set the page + */ + ret = bcm539x_set_page(bd, page); + if (ret) { + return ret; + } + + /* + * (3) Kick off the register read + */ + txbuf[0] = BCM539X_CMD_READ; + txbuf[1] = reg; + ret = spi_write_then_read(bd->spi, txbuf, 2, txbuf, 1); + if (ret) { + return ret; + } + + /* + * (4) Wait for RACK + */ + ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_RACK, 1); + if (ret) { + return ret; + } + + /* + * (5) Read the data + */ + txbuf[0] = BCM539X_CMD_READ; + txbuf[1] = BCM539X_GLOBAL_SPI_DATA0; + + ret = spi_write_then_read(bd->spi, txbuf, 2, buf, len); + +#ifdef BCM539X_DEBUG + { + int i; + printk("read page %02x reg %02x len=%d rxbuf=", + page, reg, len); + for (i = 0; i < len; i++) { + printk("%02x ", ((u8_t *)buf)[i]); + } + printk("\n"); + } +#endif + + return ret; +} + +/* + * bcm539x_read_32 + * Reads an 32 bit number from a given page and register + */ +static int bcm539x_read_32(struct bcm539x_data *bd, u8_t page, + u8_t reg, u32_t *buf) +{ + int ret = bcm539x_read_bytes(bd, page, reg, buf, 4); + *buf = le32_to_cpu(*buf); + return ret; +} + +/* + * bcm539x_read_16 + * Reads an 16 bit number from a given page and register + */ +static int bcm539x_read_16(struct bcm539x_data *bd, u8_t page, + u8_t reg, u16_t *buf) +{ + int ret = bcm539x_read_bytes(bd, page, reg, buf, 2); + *buf = le16_to_cpu(*buf); + return ret; +} + +/* + * bcm539x_read_8 + * Reads an 8 bit number from a given page and register + */ +static int bcm539x_read_8(struct bcm539x_data *bd, u8_t page, + u8_t reg, u8_t *buf) +{ + return bcm539x_read_bytes(bd, page, reg, buf, 1); +} + +/* + * bcm539x_set_mode + */ +static int bcm539x_set_mode(struct bcm539x_data *bd, int state) +{ + u8_t buf; + int ret; + + ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, &buf); + if (ret) { + return ret; + } + + buf &= ~(1 << 1); + buf |= state ? (1 << 1) : 0; + + ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, buf); + return ret; +} + +/* + * bcm539x_handle_reset + */ +static int bcm539x_handle_reset(struct switch_device *dev, char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + int ret; + + ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_SRST, + (1 << 7) | (1 << 4)); + if (ret) { + return ret; + } + + udelay(20); + + ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_SRST, 0); + return ret; +} + +/* + * bcm539x_handle_vlan_ports_read + */ +static int bcm539x_handle_vlan_ports_read(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + int j; + int len = 0; + u8_t rxbuf8; + u32_t rxbuf32; + int ret; + + ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, inst); + if (ret) { + return ret; + } + + ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, + (1 << 7) | 1); + if (ret) { + return ret; + } + + /* + * Wait for completion + */ + for (j = 0; j < BCM539X_SPI_RETRIES; j++) { + ret = bcm539x_read_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, + &rxbuf8); + if (ret) { + return ret; + } + if (!(rxbuf8 & (1 << 7))) { + break; + } + } + + if (j == BCM539X_SPI_RETRIES) { + return -EIO; + } + + /* + * Read the table entry + */ + ret = bcm539x_read_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, &rxbuf32); + if (ret) { + return ret; + } + + for (j = 0; j < 9; j++) { + if (rxbuf32 & (1 << j)) { + u16_t rxbuf16; + len += sprintf(buf + len, "%d", j); + if (rxbuf32 & (1 << (j + 9))) { + buf[len++] = 'u'; + } else { + buf[len++] = 't'; + } + ret = bcm539x_read_16(bd, PAGE_VLAN, + REG_VLAN_PTAG0 + (j << 1), + &rxbuf16); + if (ret) { + return ret; + } + if (rxbuf16 == inst) { + buf[len++] = '*'; + } + buf[len++] = '\t'; + } + } + + len += sprintf(buf + len, "\n"); + buf[len] = '\0'; + + return len; +} + +/* + * bcm539x_handle_vlan_ports_write + */ +static int bcm539x_handle_vlan_ports_write(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + int j; + u32_t untag; + u32_t ports; + u32_t def; + + u8_t rxbuf8; + u16_t rxbuf16; + int ret; + + switch_parse_vlan_ports(dev, buf, &untag, &ports, &def); + +#ifdef BCM539X_DEBUG + printk(KERN_DEBUG "'%s' inst=%d untag=%08x ports=%08x def=%08x\n", + buf, inst, untag, ports, def); +#endif + + if (!ports) { + return 0; + } + + /* + * Change default vlan tag + */ + for (j = 0; j < 9; j++) { + if ((untag | def) & (1 << j)) { + ret = bcm539x_write_16(bd, PAGE_VLAN, + REG_VLAN_PTAG0 + (j << 1), + inst); + if (ret) { + return ret; + } + continue; + } + + if (!(dev->port_mask[0] & (1 << j))) { + continue; + } + + /* + * Remove any ports which are not listed anymore as members of + * this vlan + */ + ret = bcm539x_read_16(bd, PAGE_VLAN, + REG_VLAN_PTAG0 + (j << 1), &rxbuf16); + if (ret) { + return ret; + } + if (rxbuf16 == inst) { + ret = bcm539x_write_16(bd, PAGE_VLAN, + REG_VLAN_PTAG0 + (j << 1), 0); + if (ret) { + return ret; + } + } + } + + /* + * Write the VLAN table + */ + ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, inst); + if (ret) { + return ret; + } + + ret = bcm539x_write_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, + (untag << 9) | ports); + if (ret) { + return ret; + } + + ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, + (1 << 7) | 0); + if (ret) { + return ret; + } + + /* + * Wait for completion + */ + for (j = 0; j < BCM539X_SPI_RETRIES; j++) { + ret = bcm539x_read_bytes(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, + &rxbuf8, 1); + if (ret) { + return ret; + } + if (!(rxbuf8 & (1 << 7))) { + break; + } + } + + return (j < BCM539X_SPI_RETRIES) ? 0 : -EIO; +} + +/* + * Handlers for /vlan/ + */ +static const struct switch_handler bcm539x_switch_handlers_vlan_dir[] = { + { + .name = "ports", + .read = bcm539x_handle_vlan_ports_read, + .write = bcm539x_handle_vlan_ports_write, + }, + { + }, +}; + +/* + * bcm539x_handle_vlan_delete_write + */ +static int bcm539x_handle_vlan_delete_write(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + int vid; + u8_t rxbuf8; + u32_t txbuf; + int j; + int ret; + + vid = simple_strtoul(buf, NULL, 0); + if (!vid) { + return -EINVAL; + } + + /* + * Disable this VLAN + * + * Go through the port-based vlan registers and clear the appropriate + * ones out + */ + for (j = 0; j < 9; j++) { + u16_t rxbuf16; + ret = bcm539x_read_16(bd, PAGE_VLAN, REG_VLAN_PTAG0 + (j << 1), + &rxbuf16); + if (ret) { + return ret; + } + if (rxbuf16 == vid) { + txbuf = 0; + ret = bcm539x_write_16(bd, PAGE_VLAN, + REG_VLAN_PTAG0 + (j << 1), + txbuf); + if (ret) { + return ret; + } + } + } + + /* + * Write the VLAN table + */ + txbuf = vid; + ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, txbuf); + if (ret) { + return ret; + } + + txbuf = 0; + ret = bcm539x_write_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, txbuf); + if (ret) { + return ret; + } + + txbuf = (1 << 7) | (0); + ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, txbuf); + if (ret) { + return ret; + } + + /* + * Wait for completion + */ + for (j = 0; j < BCM539X_SPI_RETRIES; j++) { + ret = bcm539x_read_bytes(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, + &rxbuf8, 1); + if (ret) { + return ret; + } + if (!(rxbuf8 & (1 << 7))) { + break; + } + } + + if (j == BCM539X_SPI_RETRIES) { + return -EIO; + } + + return switch_remove_vlan_dir(dev, vid); +} + +/* + * bcm539x_handle_vlan_create_write + */ +static int bcm539x_handle_vlan_create_write(struct switch_device *dev, + char *buf, int inst) +{ + int vid; + + vid = simple_strtoul(buf, NULL, 0); + if (!vid) { + return -EINVAL; + } + + return switch_create_vlan_dir(dev, vid, + bcm539x_switch_handlers_vlan_dir); +} + +/* + * bcm539x_handle_enable_read + */ +static int bcm539x_handle_enable_read(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + u8_t rxbuf; + int ret; + + ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, &rxbuf); + if (ret) { + return ret; + } + rxbuf = (rxbuf & (1 << 1)) ? 1 : 0; + + return sprintf(buf, "%d\n", rxbuf); +} + +/* + * bcm539x_handle_enable_write + */ +static int bcm539x_handle_enable_write(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + + return bcm539x_set_mode(bd, buf[0] == '1'); +} + +/* + * bcm539x_handle_enable_vlan_read + */ +static int bcm539x_handle_enable_vlan_read(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + u8_t rxbuf; + int ret; + + ret = bcm539x_read_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, &rxbuf); + if (ret) { + return ret; + } + rxbuf = (rxbuf & (1 << 7)) ? 1 : 0; + + return sprintf(buf, "%d\n", rxbuf); +} + +/* + * bcm539x_handle_enable_vlan_write + */ +static int bcm539x_handle_enable_vlan_write(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + int ret; + + /* + * disable 802.1Q VLANs + */ + if (buf[0] != '1') { + ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, 0); + return ret; + } + + /* + * enable 802.1Q VLANs + * + * Enable 802.1Q | IVL learning + */ + ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, + (1 << 7) | (3 << 5)); + if (ret) { + return ret; + } + + /* + * RSV multicast fwd | RSV multicast chk + */ + ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL1, + (1 << 2) | (1 << 3)); + if (ret) { + return ret; + } +#if 0 + /* + * Drop invalid VID + */ + ret = bcm539x_write_16(bd, PAGE_VLAN, REG_VLAN_CTRL3, 0x00FF); + if (ret) { + return ret; + } +#endif + return 0; +} + +/* + * bcm539x_handle_port_enable_read + */ +static int bcm539x_handle_port_enable_read(struct switch_device *dev, + char *buf, int inst) +{ + return sprintf(buf, "%d\n", 1); +} + +/* + * bcm539x_handle_port_enable_write + */ +static int bcm539x_handle_port_enable_write(struct switch_device *dev, + char *buf, int inst) +{ + /* + * validate port + */ + if (!(dev->port_mask[0] & (1 << inst))) { + return -EIO; + } + + if (buf[0] != '1') { + printk(KERN_WARNING "switch port[%d] disabling is not supported\n", inst); + } + return 0; +} + +/* + * bcm539x_handle_port_state_read + */ +static int bcm539x_handle_port_state_read(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + int ret; + u16_t link; + + /* + * validate port + */ + if (!(dev->port_mask[0] & (1 << inst))) { + return -EIO; + } + + /* + * check PHY link state - CPU port (port 8) is always up + */ + ret = bcm539x_read_16(bd, PAGE_STATUS, REG_LINK_STATUS, &link); + if (ret) { + return ret; + } + link |= (1 << 8); + + return sprintf(buf, "%d\n", (link & (1 << inst)) ? 1 : 0); +} + +/* + * bcm539x_handle_port_media_read + */ +static int bcm539x_handle_port_media_read(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + int ret; + u16_t link, duplex; + u32_t speed; + + /* + * validate port + */ + if (!(dev->port_mask[0] & (1 << inst))) { + return -EIO; + } + + /* + * check PHY link state first - CPU port (port 8) is always up + */ + ret = bcm539x_read_16(bd, PAGE_STATUS, REG_LINK_STATUS, &link); + if (ret) { + return ret; + } + link |= (1 << 8); + + if (!(link & (1 << inst))) { + return sprintf(buf, "UNKNOWN\n"); + } + + /* + * get link speeda dn duplex - CPU port (port 8) is 1000/full + */ + ret = bcm539x_read_32(bd, PAGE_STATUS, 4, &speed); + if (ret) { + return ret; + } + speed |= (2 << 16); + speed = (speed >> (2 * inst)) & 3; + + ret = bcm539x_read_16(bd, PAGE_STATUS, 8, &duplex); + if (ret) { + return ret; + } + duplex |= (1 << 8); + duplex = (duplex >> inst) & 1; + + return sprintf(buf, "%d%cD\n", + (speed == 0) ? 10 : ((speed == 1) ? 100 : 1000), + duplex ? 'F' : 'H'); +} + +/* + * bcm539x_handle_port_meida_write + */ +static int bcm539x_handle_port_meida_write(struct switch_device *dev, + char *buf, int inst) +{ + struct bcm539x_data *bd = + (struct bcm539x_data *)switch_get_drvdata(dev); + int ret; + u16_t ctrl_word, local_cap, local_giga_cap; + + /* + * validate port (not for CPU port) + */ + if (!(dev->port_mask[0] & (1 << inst) & ~(1 << 8))) { + return -EIO; + } + + /* + * Get the maximum capability from status + * SPI reg[0x00] = PHY[0x0] --- MII control + * SPI reg[0x08] = PHY[0x4] --- MII local capability + * SPI reg[0x12] = PHY[0x9] --- GMII control + */ + ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_ADVERTISE << 1), &local_cap); + if (ret) { + return ret; + } + ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_CTRL1000 << 1), &local_giga_cap); + if (ret) { + return ret; + } + + /* Configure to the requested speed */ + if (strncmp(buf, "1000FD", 6) == 0) { + /* speed */ + local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL); + local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL); + local_giga_cap |= (ADVERTISE_1000HALF | ADVERTISE_1000FULL); + /* duplex */ + } else if (strncmp(buf, "100FD", 5) == 0) { + /* speed */ + local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL); + local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL); + local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + /* duplex */ + local_cap &= ~(ADVERTISE_100HALF); + } else if (strncmp(buf, "100HD", 5) == 0) { + /* speed */ + local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL); + local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL); + local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + /* duplex */ + local_cap &= ~(ADVERTISE_100FULL); + } else if (strncmp(buf, "10FD", 4) == 0) { + /* speed */ + local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL); + local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL); + local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + /* duplex */ + local_cap &= ~(ADVERTISE_10HALF); + } else if (strncmp(buf, "10HD", 4) == 0) { + /* speed */ + local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL); + local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL); + local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + /* duplex */ + local_cap &= ~(ADVERTISE_10FULL); + } else if (strncmp(buf, "AUTO", 4) == 0) { + /* speed */ + local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL); + local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL); + local_giga_cap |= (ADVERTISE_1000HALF | ADVERTISE_1000FULL); + } else { + return -EINVAL; + } + + /* Active PHY with the requested speed for auto-negotiation */ + ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_ADVERTISE << 1), local_cap); + if (ret) { + return ret; + } + ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_CTRL1000 << 1), local_giga_cap); + if (ret) { + return ret; + } + + ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_BMCR << 1), &ctrl_word); + if (ret) { + return ret; + } + ctrl_word |= (BMCR_ANENABLE | BMCR_ANRESTART); + ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_BMCR << 1), ctrl_word); + if (ret) { + return ret; + } + + return 0; +} + +/* + * proc_fs entries for this switch + */ +static const struct switch_handler bcm539x_switch_handlers[] = { + { + .name = "enable", + .read = bcm539x_handle_enable_read, + .write = bcm539x_handle_enable_write, + }, + { + .name = "enable_vlan", + .read = bcm539x_handle_enable_vlan_read, + .write = bcm539x_handle_enable_vlan_write, + }, + { + .name = "reset", + .write = bcm539x_handle_reset, + }, + { + }, +}; + +/* + * Handlers for /vlan + */ +static const struct switch_handler bcm539x_switch_handlers_vlan[] = { + { + .name = "delete", + .write = bcm539x_handle_vlan_delete_write, + }, + { + .name = "create", + .write = bcm539x_handle_vlan_create_write, + }, + { + }, +}; + +/* + * Handlers for /port/ + */ +static const struct switch_handler bcm539x_switch_handlers_port[] = { + { + .name = "enable", + .read = bcm539x_handle_port_enable_read, + .write = bcm539x_handle_port_enable_write, + }, + { + .name = "state", + .read = bcm539x_handle_port_state_read, + }, + { + .name = "media", + .read = bcm539x_handle_port_media_read, + .write = bcm539x_handle_port_meida_write, + }, + { + }, +}; + +/* + * bcm539x_probe + */ +static int __devinit bcm539x_probe(struct spi_device *spi) +{ + struct bcm539x_data *bd; + struct switch_core_platform_data *pdata; + struct switch_device *switch_dev = NULL; + int i, ret; + u8_t txbuf[2]; + + pdata = spi->dev.platform_data; + if (!pdata) { + return -EINVAL; + } + + ret = spi_setup(spi); + if (ret < 0) { + return ret; + } + + /* + * Reset the chip if requested + */ + if (pdata->flags & SWITCH_DEV_FLAG_HW_RESET) { + ret = gpio_request(pdata->pin_reset, "switch-bcm539x-reset"); + if (ret) { + printk(KERN_WARNING "Could not request reset\n"); + return -EINVAL; + } + + gpio_direction_output(pdata->pin_reset, 0); + udelay(10); + gpio_set_value(pdata->pin_reset, 1); + udelay(20); + } + + /* + * Allocate our private data structure + */ + bd = kzalloc(sizeof(struct bcm539x_data), GFP_KERNEL); + if (!bd) { + return -ENOMEM; + } + + dev_set_drvdata(&spi->dev, bd); + bd->pdata = pdata; + bd->spi = spi; + bd->last_page = 0xFF; + + /* + * First perform SW reset if needed + */ + if (pdata->flags & SWITCH_DEV_FLAG_SW_RESET) { + txbuf[0] = (1 << 7) | (1 << 4); + ret = bcm539x_write_bytes(bd, PAGE_PORT_TC, + REG_CTRL_SRST, txbuf, 1); + if (ret) { + goto fail; + } + + udelay(20); + + txbuf[0] = 0; + ret = bcm539x_write_bytes(bd, PAGE_PORT_TC, + REG_CTRL_SRST, txbuf, 1); + if (ret) { + goto fail; + } + } + + /* + * See if we can see the chip + */ + for (i = 0; i < 10; i++) { + ret = bcm539x_read_bytes(bd, PAGE_MMR, REG_DEVICE_ID, + &bd->device_id, 1); + if (!ret) { + break; + } + } + if (ret) { + goto fail; + } + + /* + * We only support 5395, 5397, 5398 + */ + if ((bd->device_id != 0x95) && (bd->device_id != 0x97) && + (bd->device_id != 0x98)) { + ret = -ENODEV; + goto fail; + } + + /* + * Override CPU port config: fixed link @1000 with flow control + */ + ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MIIPO, txbuf); + bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_MIIPO, 0xbb); // Override IMP port config + printk("Broadcom SW CPU port setting: 0x%x -> 0xbb\n", txbuf[0]); + + /* + * Setup the switch driver structure + */ + switch_dev = switch_alloc(); + if (!switch_dev) { + ret = -ENOMEM; + goto fail; + } + switch_dev->name = pdata->name; + + switch_dev->ports = (bd->device_id == 0x98) ? 9 : 6; + switch_dev->port_mask[0] = (bd->device_id == 0x98) ? 0x1FF : 0x11F; + switch_dev->driver_handlers = bcm539x_switch_handlers; + switch_dev->reg_handlers = NULL; + switch_dev->vlan_handlers = bcm539x_switch_handlers_vlan; + switch_dev->port_handlers = bcm539x_switch_handlers_port; + + bd->switch_dev = switch_dev; + switch_set_drvdata(switch_dev, (void *)bd); + + ret = switch_register(bd->switch_dev); + if (ret < 0) { + goto fail; + } + + printk(KERN_INFO "bcm53%02x switch chip initialized\n", bd->device_id); + + return ret; + +fail: + if (switch_dev) { + switch_release(switch_dev); + } + dev_set_drvdata(&spi->dev, NULL); + kfree(bd); + return ret; +} + +static int __attribute__((unused)) bcm539x_remove(struct spi_device *spi) +{ + struct bcm539x_data *bd; + + bd = dev_get_drvdata(&spi->dev); + + if (bd->pdata->flags & SWITCH_DEV_FLAG_HW_RESET) { + gpio_free(bd->pdata->pin_reset); + } + + if (bd->switch_dev) { + switch_unregister(bd->switch_dev); + switch_release(bd->switch_dev); + } + + dev_set_drvdata(&spi->dev, NULL); + + kfree(bd); + + return 0; +} + +static struct spi_driver bcm539x_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = bcm539x_probe, + .remove = __devexit_p(bcm539x_remove), +}; + +static int __init bcm539x_init(void) +{ + return spi_register_driver(&bcm539x_driver); +} + +module_init(bcm539x_init); + +static void __exit bcm539x_exit(void) +{ + spi_unregister_driver(&bcm539x_driver); +} +module_exit(bcm539x_exit); + +MODULE_AUTHOR("Pat Tjin"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("bcm539x SPI switch chip driver"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.c new file mode 100644 index 000000000..855aa068d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.c @@ -0,0 +1,737 @@ +/* + * arch/ubicom32/mach-common/switch-core.c + * Ubicom32 architecture switch and /proc/switch/... implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2005 Felix Fietkau + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * + * Basic doc of driver's /proc interface: + * /proc/switch// + * registers: read-only + * counters: read-only + * reset: write causes hardware reset + * enable: "0", "1" + * enable_vlan: "0", "1" + * port// + * enabled: "0", "1" + * link state: read-only + * media: "AUTO", "1000FD", "100FD", "100HD", "10FD", "10HD" + * vlan// + * ports: same syntax as for nvram's vlan*ports (eg. "1 2 3 4 5*") + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "switch-core.h" + +/* + * Pointer to the root of our filesystem + */ +static struct proc_dir_entry *switch_root; + +/* + * Lock used to manage access to the switch list + */ +DECLARE_RWSEM(switch_list_lock); +EXPORT_SYMBOL_GPL(switch_list_lock); + +/* + * List of switches we are managing + */ +LIST_HEAD(switch_list); +EXPORT_SYMBOL_GPL(switch_list); + +/* + * List of handlers we have + */ +LIST_HEAD(switch_handler_list); +EXPORT_SYMBOL_GPL(switch_handler_list); + +/* + * Keep track of all the handlers we added + */ +struct switch_handler_entry { + struct list_head node; + struct proc_dir_entry *parent; + struct switch_device *dev; + const struct switch_handler *handler; + int inst; +}; + +/* + * Keep track of all VLAN dirs we created + */ +struct switch_vlan_entry { + struct list_head node; + struct proc_dir_entry *pde; + int vlan_id; + const struct switch_handler *handlers; +}; + +/* + * switch_parse_vlan_ports + * Parse the vlan properties written to /vlan//ports + */ +void switch_parse_vlan_ports(struct switch_device *switch_dev, + char *buf, u32_t *untag, + u32_t *ports, u32_t *def) +{ + u32_t tag = 0; + *untag = 0; + *ports = 0; + *def = 0; + + + /* + * Skip any leading spaces + */ + while (isspace(*buf)) { + buf++; + } + + /* + * Parse out the string + */ + while (*buf) { + u32_t port = simple_strtoul(buf, &buf, 10); + u32_t mask = (1 << port); + + /* + * Parse out any flags + */ + while (*buf && !isspace(*buf)) { + switch (*buf++) { + case 't': + tag |= mask; + break; + case '*': + *def |= mask; + break; + } + } + *ports |= mask; + + /* + * Skip any spaces + */ + while (isspace(*buf)) { + buf++; + } + } + + *untag = ~tag & *ports; +} + +/* + * switch_proc_read + * Handle reads from the procfs, dispatches the driver specific handler + */ +static ssize_t switch_proc_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode); + char *page; + int len = 0; + + page = kmalloc(SWITCH_MAX_BUFSZ, GFP_KERNEL); + if (!page) { + return -ENOBUFS; + } + + if (pde->data != NULL) { + struct switch_handler_entry *she = + (struct switch_handler_entry *)pde->data; + if (she->handler->read) { + len += she->handler->read(she->dev, page + len, + she->inst); + } + } + len += 1; + + if (*ppos < len) { + len = min_t(int, len - *ppos, count); + if (copy_to_user(buf, (page + *ppos), len)) { + kfree(page); + return -EFAULT; + } + *ppos += len; + } else { + len = 0; + } + + kfree(page); + + return len; +} + +/* + * switch_proc_write + * Handle writes from the procfs, dispatches the driver specific handler + */ +static ssize_t switch_proc_write(struct file *file, const char *buf, + size_t count, loff_t *data) +{ + struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode); + char *page; + int ret = -EINVAL; + + page = kmalloc(count + 1, GFP_KERNEL); + if (page == NULL) + return -ENOBUFS; + + if (copy_from_user(page, buf, count)) { + kfree(page); + return -EINVAL; + } + page[count] = 0; + + if (pde->data != NULL) { + struct switch_handler_entry *she = + (struct switch_handler_entry *)pde->data; + if (she->handler->write) { + ret = she->handler->write(she->dev, page, she->inst); + if (ret >= 0) { + ret = count; + } + } + } + + kfree(page); + return ret; +} + +/* + * File operations for the proc_fs, we must cast here since proc_fs' definitions + * differ from file_operations definitions. + */ +static struct file_operations switch_proc_fops = { + .read = (ssize_t (*) (struct file *, char __user *, + size_t, loff_t *))switch_proc_read, + .write = (ssize_t (*) (struct file *, const char __user *, + size_t, loff_t *))switch_proc_write, +}; + +/* + * switch_add_handler + */ +static int switch_add_handler(struct switch_device *switch_dev, + struct proc_dir_entry *parent, + const struct switch_handler *handler, + int inst) +{ + struct switch_handler_entry *she; + struct proc_dir_entry *pde; + int mode; + + she = (struct switch_handler_entry *) + kzalloc(sizeof(struct switch_handler_entry), GFP_KERNEL); + if (!she) { + return -ENOMEM; + } + + INIT_LIST_HEAD(&she->node); + she->parent = parent; + she->dev = switch_dev; + she->inst = inst; + she->handler = handler; + list_add(&she->node, &switch_dev->handlers); + + mode = 0; + if (handler->read != NULL) { + mode |= S_IRUSR; + } + if (handler->write != NULL) { + mode |= S_IWUSR; + } + + pde = create_proc_entry(handler->name, mode, parent); + if (!pde) { + kfree(she); + printk("Failed to create node '%s' in parent %p\n", + handler->name, parent); + return -ENOMEM; + } + pde->data = (void *)she; + pde->proc_fops = &switch_proc_fops; + + return 0; +} + +/* + * switch_add_handlers + */ +static int switch_add_handlers(struct switch_device *switch_dev, + struct proc_dir_entry *parent, + const struct switch_handler *handlers, + int inst) +{ + while (handlers->name) { + int ret = switch_add_handler(switch_dev, + parent, handlers, inst); + if (ret) { + return ret; + } + handlers++; + } + + return 0; +} + +/* + * switch_remove_vlan_dirs + * Removes all vlan directories + * + * Assumes all vlan directories are empty, should be called after + * switch_remove_handlers + */ +static void switch_remove_vlan_dirs(struct switch_device *switch_dev) +{ + struct list_head *pos; + struct list_head *tmp; + struct switch_vlan_entry *sve; + + list_for_each_safe(pos, tmp, &switch_dev->vlan_dirs) { + sve = list_entry(pos, struct switch_vlan_entry, node); + list_del(pos); + remove_proc_entry(sve->pde->name, switch_dev->vlan_dir); + kfree(sve); + } +} + +/* + * switch_remove_handlers + * Removes all handlers registered to the given switch_device + */ +static void switch_remove_handlers(struct switch_device *switch_dev) +{ + struct list_head *pos; + struct list_head *tmp; + struct switch_handler_entry *she; + + list_for_each_safe(pos, tmp, &switch_dev->handlers) { + she = list_entry(pos, struct switch_handler_entry, node); + list_del(pos); + remove_proc_entry(she->handler->name, she->parent); + kfree(she); + } +} + +/* + * switch_unregister_proc_nodes + * Unregisters all proc nodes related to switch_dev + */ +void switch_unregister_proc_nodes(struct switch_device *switch_dev) +{ + switch_remove_handlers(switch_dev); + + if (switch_dev->port_dirs) { + int i; + + for (i = 0; i < switch_dev->ports; i++) { + if (switch_dev->port_dirs[i]) { + remove_proc_entry( + switch_dev->port_dirs[i]->name, + switch_dev->port_dir); + } + } + } + + if (switch_dev->port_dir) { + remove_proc_entry("port", switch_dev->driver_dir); + switch_dev->port_dir = NULL; + } + + if (switch_dev->reg_dir) { + remove_proc_entry("reg", switch_dev->reg_dir); + switch_dev->reg_dir = NULL; + } + + if (switch_dev->vlan_dir) { + switch_remove_vlan_dirs(switch_dev); + remove_proc_entry("vlan", switch_dev->driver_dir); + switch_dev->vlan_dir = NULL; + } + + if (switch_dev->driver_dir) { + remove_proc_entry(switch_dev->name, switch_root); + switch_dev->driver_dir = NULL; + } +} + +/* + * switch_remove_vlan_dir + * Removes vlan dir in switch//vlan/ + */ +int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id) +{ + struct list_head *pos; + struct switch_vlan_entry *sve = NULL; + + list_for_each(pos, &switch_dev->vlan_dirs) { + struct switch_vlan_entry *tmp = + list_entry(pos, struct switch_vlan_entry, node); + if (tmp->vlan_id == vlan_id) { + sve = tmp; + break; + } + } + + if (!sve) { + return -ENOENT; + } + + /* + * Remove it from the list + */ + list_del(pos); + + /* + * Remove the handlers + */ + while (sve->handlers->name) { + remove_proc_entry(sve->handlers->name, sve->pde); + sve->handlers++; + } + + /* + * Remove the proc entry for the dir + */ + remove_proc_entry(sve->pde->name, switch_dev->vlan_dir); + + kfree(sve); + + return 0; +} + +/* + * switch_create_vlan_dir + * Creates vlan dir in switch//vlan/ + */ +int switch_create_vlan_dir(struct switch_device *switch_dev, + int vlan_id, const struct switch_handler *handlers) +{ + char s[14]; + struct proc_dir_entry *pde = NULL; + struct switch_vlan_entry *sve = NULL; + int ret; + struct list_head *pos; + + /* + * Check to see if it exists already + */ + list_for_each(pos, &switch_dev->vlan_dirs) { + sve = list_entry(pos, struct switch_vlan_entry, node); + if (sve->vlan_id == vlan_id) { + return -EEXIST; + } + } + sve = NULL; + + /* + * Create the vlan directory if we didn't have it before + */ + if (!switch_dev->vlan_dir) { + switch_dev->vlan_dir = proc_mkdir("vlan", + switch_dev->driver_dir); + if (!switch_dev->vlan_dir) { + goto fail; + } + if (switch_dev->vlan_handlers) { + ret = switch_add_handlers(switch_dev, + switch_dev->vlan_dir, + switch_dev->vlan_handlers, 0); + if (ret) { + goto fail; + } + } + } + + /* + * Create the vlan_id directory + */ + snprintf(s, 14, "%d", vlan_id); + pde = proc_mkdir(s, switch_dev->vlan_dir); + if (!pde) { + goto fail; + } + + /* + * Create the handlers for this vlan + */ + if (handlers) { + ret = switch_add_handlers(switch_dev, pde, handlers, vlan_id); + if (ret) { + goto fail; + } + } + + /* + * Keep track of all the switch vlan entries created + */ + sve = (struct switch_vlan_entry *) + kzalloc(sizeof(struct switch_vlan_entry), GFP_KERNEL); + if (!sve) { + goto fail; + } + INIT_LIST_HEAD(&sve->node); + sve->handlers = handlers; + sve->vlan_id = vlan_id; + sve->pde = pde; + list_add(&sve->node, &switch_dev->vlan_dirs); + + return 0; + +fail: + if (sve) { + kfree(sve); + } + + if (pde) { + /* + * Remove any proc entries we might have created + */ + while (handlers->name) { + remove_proc_entry(handlers->name, pde); + handlers++; + } + + remove_proc_entry(s, switch_dev->driver_dir); + } + + return -ENOMEM; +} + +/* + * switch_register_proc_nodes + */ +int switch_register_proc_nodes(struct switch_device *switch_dev) +{ + int i; + int n; + + switch_dev->port_dirs = kzalloc(switch_dev->ports * + sizeof(struct proc_dir_entry *), + GFP_KERNEL); + if (!switch_dev->port_dirs) { + return -ENOMEM; + } + + /* + * Create a new proc entry for this switch + */ + switch_dev->driver_dir = proc_mkdir(switch_dev->name, switch_root); + if (!switch_dev->driver_dir) { + goto fail; + } + if (switch_dev->driver_handlers) { + switch_add_handlers(switch_dev, + switch_dev->driver_dir, + switch_dev->driver_handlers, + 0); + } + + /* + * Create the ports + */ + switch_dev->port_dir = proc_mkdir("port", switch_dev->driver_dir); + if (!switch_dev->port_dir) { + goto fail; + } + for (n = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) { + if (switch_dev->port_mask[i / 32] & (1 << i % 32)) { + char s[14]; + + snprintf(s, 14, "%d", i); + switch_dev->port_dirs[n] = + proc_mkdir(s, switch_dev->port_dir); + if (!switch_dev->port_dirs[n]) { + goto fail; + } + if (switch_dev->port_handlers) { + switch_add_handlers(switch_dev, + switch_dev->port_dirs[n], + switch_dev->port_handlers, + i); + } + n++; + } + } + + /* + * Create the register directory for switch register access. + */ + if (switch_dev->reg_handlers) { + switch_dev->reg_dir = proc_mkdir("reg", switch_dev->driver_dir); + if (!switch_dev->reg_dir) { + goto fail; + } + + switch_add_handlers(switch_dev, + switch_dev->reg_dir, + switch_dev->reg_handlers, + 0); + } + + /* + * Create the vlan directory + */ + if (switch_dev->vlan_handlers) { + switch_dev->vlan_dir = proc_mkdir("vlan", + switch_dev->driver_dir); + if (!switch_dev->vlan_dir) { + goto fail; + } + if (switch_dev->vlan_handlers) { + switch_add_handlers(switch_dev, + switch_dev->vlan_dir, + switch_dev->vlan_handlers, + 0); + } + } + + return 0; + +fail: + switch_unregister_proc_nodes(switch_dev); + return -ENOMEM; +} + +/* + * switch_release + */ +void switch_release(struct switch_device *switch_dev) +{ + kfree(switch_dev); +} + +/* + * switch_alloc + */ +struct switch_device *switch_alloc(void) +{ + struct switch_device *switch_dev = + kzalloc(sizeof(struct switch_device), + GFP_KERNEL); + INIT_LIST_HEAD(&switch_dev->node); + INIT_LIST_HEAD(&switch_dev->vlan_dirs); + INIT_LIST_HEAD(&switch_dev->handlers); + return switch_dev; +} + +/* + * switch_register + */ +int switch_register(struct switch_device *switch_dev) +{ + int ret; + int i; + + /* + * Make sure that the number of ports and the port mask make sense + */ + for (ret = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) { + if (switch_dev->port_mask[i / 32] & (1 << i % 32)) { + ret++; + } + } + if (ret > switch_dev->ports) { + return -EINVAL; + } + + /* + * Create the /proc entries + */ + ret = switch_register_proc_nodes(switch_dev); + if (ret) { + return ret; + } + + /* + * Add it to the list of switches + */ + down_write(&switch_list_lock); + list_add_tail(&switch_dev->node, &switch_list); + up_write(&switch_list_lock); + + printk(KERN_INFO "Registered switch device: %s\n", switch_dev->name); + + return 0; +} +EXPORT_SYMBOL_GPL(switch_register); + +/* + * switch_unregister + * Unregisters a previously registered switch_device object + */ +void switch_unregister(struct switch_device *switch_dev) +{ + /* + * remove the proc entries + */ + switch_unregister_proc_nodes(switch_dev); + + /* + * Remove it from the list of switches + */ + down_write(&switch_list_lock); + list_del(&switch_dev->node); + up_write(&switch_list_lock); + + printk(KERN_INFO "Unregistered switch device: %s\n", switch_dev->name); +} +EXPORT_SYMBOL_GPL(switch_unregister); + +/* + * switch_init + */ +static int __init switch_init(void) +{ + switch_root = proc_mkdir("switch", NULL); + if (!switch_root) { + printk(KERN_WARNING "Failed to make root switch node\n"); + return -ENODEV; + } + return 0; +} +module_init(switch_init); + +/* + * switch_exit + */ +static void __exit switch_exit(void) +{ + remove_proc_entry("switch", NULL); +} +module_exit(switch_exit); + +MODULE_AUTHOR("Patrick Tjin"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Ethernet Switch Class Interface"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.h new file mode 100644 index 000000000..1e18b1cba --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.h @@ -0,0 +1,92 @@ +/* + * arch/ubicom32/mach-common/switch-core.h + * Private data for the switch module + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _SWITCH_CORE_H_ +#define _SWITCH_CORE_H_ + +struct switch_handler_entry; +struct switch_vlan_entry; + +#define SWITCH_PORT_MASK_SIZE 2 + +struct switch_device { + struct list_head node; + + const char *name; + void *drvdata; + + u8_t ports; + + struct proc_dir_entry *driver_dir; + const struct switch_handler *driver_handlers; + + struct proc_dir_entry *port_dir; + struct proc_dir_entry **port_dirs; + const struct switch_handler *port_handlers; + + struct proc_dir_entry *reg_dir; + const struct switch_handler *reg_handlers; + + struct proc_dir_entry *vlan_dir; + const struct switch_handler *vlan_handlers; + struct list_head vlan_dirs; + + struct list_head handlers; + + u32_t port_mask[SWITCH_PORT_MASK_SIZE]; +}; + +typedef int (*switch_handler_fn)(struct switch_device *, char *buf, int nr); +struct switch_handler { + const char *name; + + switch_handler_fn read; + switch_handler_fn write; +}; + +#define SWITCH_MAX_BUFSZ 4096 + +static inline void switch_set_drvdata(struct switch_device *switch_dev, void *drvdata) +{ + switch_dev->drvdata = drvdata; +} + +static inline void *switch_get_drvdata(struct switch_device *switch_dev) +{ + return switch_dev->drvdata; +} + +extern int switch_create_vlan_dir(struct switch_device *switch_dev, int vlan_id, const struct switch_handler *handlers); +extern int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id); +extern void switch_parse_vlan_ports(struct switch_device *switch_dev, char *buf, u32_t *untag, u32_t *ports, u32_t *def); + +extern void switch_release(struct switch_device *switch_dev); +extern struct switch_device *switch_alloc(void); +extern int switch_register(struct switch_device *switch_dev); +extern void switch_unregister(struct switch_device *switch_dev); + +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubi32-gpio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubi32-gpio.c new file mode 100644 index 000000000..5fa22f52b --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubi32-gpio.c @@ -0,0 +1,411 @@ +/* + * arch/ubicom32/mach-common/ubi32-gpio.c + * Ubicom gpio driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_PROC_FS) +#include +#endif + +#include +#include +#include + +#define UBI_GPIO_CHECK_RANGE 0 /* !0 enables range checking */ + + +/* + * Each I/O port can be configured to operate in one of several + * functional modes. One of these modes is GPIO, which causes the + * entire port to function as a GPIO port. Since the various port + * registers serve the system with other important functions, such as + * ethernet, serial, USB, etc., it isn't advantageous to set any of + * the ports to be entirely dedicated for GPIO use. The processor + * alternatively allows individual bits of a port to be assigned to be + * used as GPIO independently from the overall port function. This + * bit-by-bit assignment is selected by setting the corresponding bit + * in the port's gpio_mask register. When set, the selected bit is + * then enabled as a GPIO. If the corresponding bit is set in the + * gpio_ctl register of the port, the bit is configured as a GPIO + * output. Otherwise, it is an input. + * + * NOTE: This driver uses the bit-by-bit GPIO function assignment + * exclusively and *never* sets the port function registers to the + * GPIO function. + * + * GPIO is not the main function of any of the I/O ports. The port + * bit widths are variable from one port to the next, determined by + * the more common I/O functions of the ports. For simplicity, this + * driver assumes all the ports are 32 bits wide regardless of the + * real bit width of the port. GPIO bits are numbered from zero to + * MAX_UBICOM_GPIOS. Within a port, the least significant bit is + * numbered bit zero, the most significant is bit 31. Since the ports + * are considered logically contiguous, GPIO #32 is the zeroth bit in + * port #1, and so on. Due to the hardware definition, there are + * large gaps in the GPIO numbers representing real pins. + * + * NOTE: It is up to the programmer to refer to the processor data + * sheet to determine which bits in which ports can be accessed and + * used for GPIO. + * + */ + + +/* There are 9 ports, A through I. Not all 32 bits in each + * port can be a GPIO, but we pretend they are. Its up to the + * programmer to refer to the processor data sheet. + */ +#define MAX_UBICOM_GPIOS (9 * 32) /* ARCH_NR_GPIOS */ +#define NUM_GPIO_PORTS (gpio_bank(MAX_UBICOM_GPIOS)) + + +/* GPIO reservation bit map array */ +static int reserved_gpio_map[NUM_GPIO_PORTS]; + + +/* Array of hardware io_port addresses */ +static struct ubicom32_io_port *gpio_bank_addr[NUM_GPIO_PORTS] = +{ + UBICOM32_IO_PORT(RA), + UBICOM32_IO_PORT(RB), + UBICOM32_IO_PORT(RC), + UBICOM32_IO_PORT(RD), + UBICOM32_IO_PORT(RE), + UBICOM32_IO_PORT(RF), + UBICOM32_IO_PORT(RG), + UBICOM32_IO_PORT(RH), + UBICOM32_IO_PORT(RI) +}; + + +struct ubi_gpio_chip { + /* + * Right now, nothing else lives here. + */ + struct gpio_chip gpio_chip; +}; + + +#if UBI_GPIO_CHECK_RANGE +inline int check_gpio(unsigned gpio) +{ + if (gpio >= MAX_UBICOM_GPIOS) + return -EINVAL; + return 0; +} +#else +#define check_gpio(n) (0) +#endif + +/* + * ubi_gpio_get_port + * Get the IO port associated with a certain gpio + */ +struct ubicom32_io_port *ubi_gpio_get_port(unsigned gpio) +{ + if (gpio_bank(gpio) > NUM_GPIO_PORTS) { + return NULL; + } + return gpio_bank_addr[gpio_bank(gpio)]; +} + +/* + * ubi_gpio_error() + */ +static void ubi_gpio_error(unsigned gpio) +{ + printk(KERN_ERR "ubicom-gpio: GPIO %d wasn't requested!\n", gpio); +} + +/* + * ubi_port_setup() + */ +static void ubi_port_setup(unsigned gpio, unsigned short usage) +{ + if (!check_gpio(gpio)) { + if (usage) { + UBICOM32_GPIO_ENABLE(gpio); + } else { + UBICOM32_GPIO_DISABLE(gpio); + } + } +} + +/* + * ubi_gpio_request() + */ +static int ubi_gpio_request(struct gpio_chip *chip, unsigned gpio) +{ + unsigned long flags; + + if (check_gpio(gpio) < 0) + return -EINVAL; + + local_irq_save(flags); + + if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + printk(KERN_ERR "ubi-gpio: GPIO %d is already reserved!\n", + gpio); + local_irq_restore(flags); + return -EBUSY; + } + + reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); + + ubi_port_setup(gpio, 1); + + local_irq_restore(flags); + + return 0; +} + +/* + * ubi_gpio_free() + */ +static void ubi_gpio_free(struct gpio_chip *chip, unsigned gpio) +{ + unsigned long flags; + + if (check_gpio(gpio) < 0) + return; + + local_irq_save(flags); + + if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { + ubi_gpio_error(gpio); + local_irq_restore(flags); + return; + } + + /* Assert the pin is no longer claimed */ + reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); + + /* Revert port bit to use specified by port->function */ + ubi_port_setup(gpio, 0); + + local_irq_restore(flags); +} + +/* + * ubi_gpio_direction_input() + */ +static int ubi_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + unsigned long flags; + + if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + ubi_gpio_error(gpio); + return -EINVAL; + } + + local_irq_save(flags); + + /* Configure pin as gpio */ + ubi_port_setup(gpio, 1); + + /* Assert pin is an input */ + UBICOM32_GPIO_SET_PIN_INPUT(gpio); + + local_irq_restore(flags); + + return 0; +} + + +/* + * ubi_gpio_direction_output() + */ +static int ubi_gpio_direction_output(struct gpio_chip *chip, + unsigned gpio, int value) +{ + unsigned long flags; + + if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + ubi_gpio_error(gpio); + return -EINVAL; + } + + local_irq_save(flags); + + /* Configure pin as gpio and set initial value in gpio_out register + * so that when we enable it as an output, it will have the correct + * initial value. + */ + ubi_port_setup(gpio, 1); + if (value) { + UBICOM32_GPIO_SET_PIN_HIGH(gpio); + } else { + UBICOM32_GPIO_SET_PIN_LOW(gpio); + } + + /* Enable the pin as an output */ + UBICOM32_GPIO_SET_PIN_OUTPUT(gpio); + + local_irq_restore(flags); + + return 0; +} + + +/* + * ubi_gpio_get_value() + */ +static int ubi_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + return 0 != (gpio_bank_addr[gpio_bank(gpio)]->gpio_in & gpio_bit(gpio)); +} + + +/* + * ubi_gpio_set_value() + */ +static void ubi_gpio_set_value(struct gpio_chip *chip, unsigned gpio, + int arg) +{ + unsigned long flags; + local_irq_save(flags); + + if (arg) { + UBICOM32_GPIO_SET_PIN_HIGH(gpio); + } else { + UBICOM32_GPIO_SET_PIN_LOW(gpio); + } + + local_irq_restore(flags); +} + + +/* + * ubi_gpio_to_irq() + */ +static int ubi_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + return gpio_to_irq(gpio); +} + + +/* + * ubi_gpio_init() + */ +int __init ubi_gpio_init(void) +{ + int k; + int status; + struct ubi_gpio_chip *chip; + struct gpio_chip *gc; + + printk(KERN_INFO "Ubicom GPIO Controller\n"); + + chip = kzalloc(sizeof(struct ubi_gpio_chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + gc = &chip->gpio_chip; + gc->request = ubi_gpio_request; + gc->free = ubi_gpio_free; + gc->to_irq = ubi_gpio_to_irq; + gc->direction_input = ubi_gpio_direction_input; + gc->direction_output = ubi_gpio_direction_output; + gc->get = ubi_gpio_get_value; + gc->set = ubi_gpio_set_value; + gc->can_sleep = 0; + gc->base = 0; + gc->ngpio = MAX_UBICOM_GPIOS; /* ARCH_NR_GPIOS - 1 */ + gc->label = "ubi_gpio"; + + status = gpiochip_add(gc); + if (status != 0) { + kfree(chip); + return status; + } + + /* Assert all pins are free */ + for (k = 0; k < NUM_GPIO_PORTS; k++) { + reserved_gpio_map[k] = 0; + } + + return 0; +} + +#if defined(CONFIG_PROC_FS) +/* + * ubi_get_gpio_dir() + */ +static int ubi_get_gpio_dir(unsigned gpio) +{ + if (gpio_bank_addr[gpio_bank(gpio)]->gpio_ctl & gpio_bit(gpio)) + return 1; + else + return 0; +} + +/* + * gpio_proc_read() + */ +static int ubi_gpio_proc_read(char *buf, char **start, off_t offset, + int len, int *unused_i, void *unused_v) +{ + int c, outlen = 0; + + for (c = 0; c < MAX_UBICOM_GPIOS; c++) { + if (!check_gpio(c) && + (reserved_gpio_map[gpio_bank(c)] & gpio_bit(c))) { + len = sprintf(buf, "GPIO_%d:\t\tGPIO %s\n", c, + ubi_get_gpio_dir(c) ? "OUTPUT" : "INPUT"); + } else { + continue; + } + + buf += len; + outlen += len; + } + return outlen; +} + +/* + * ubi_gpio_register_proc() + */ +static __init int ubi_gpio_register_proc(void) +{ + struct proc_dir_entry *proc_gpio; + + proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL); + if (proc_gpio) + proc_gpio->read_proc = ubi_gpio_proc_read; + + return proc_gpio != NULL; +} +device_initcall(ubi_gpio_register_proc); +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32hid.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32hid.c new file mode 100644 index 000000000..3318eff88 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32hid.c @@ -0,0 +1,557 @@ +/* + * arch/ubicom32/mach-common/ubicom32hid.c + * I2C driver for HID coprocessor found on some DPF implementations. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "ubicom32hid" + +#ifdef DEBUG +static int ubicom32hid_debug; +#endif + +static const struct i2c_device_id ubicom32hid_id[] = { + { DRIVER_NAME, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ubicom32hid_id); + +/* + * Define this to make IR checking strict, in general, it's not needed + */ +#undef UBICOM32HID_STRICT_IR_CHECK + +#define UBICOM32HID_CMD_SET_PWM 0x01 +#define UBICOM32HID_CMD_SET_BL_EN 0x02 +#define UBICOM32HID_BL_EN_LOW 0x00 +#define UBICOM32HID_BL_EN_HIZ 0x01 +#define UBICOM32HID_BL_EN_HI 0x02 +#define UBICOM32HID_CMD_FLUSH 0x99 +#define UBICOM32HID_CMD_RESET 0x99 +#define UBICOM32HID_CMD_GET_IR_SWITCH 0xC0 +#define UBICOM32HID_CMD_GET_REVISION 0xfd +#define UBICOM32HID_CMD_GET_DEVICE_ID 0xfe +#define UBICOM32HID_CMD_GET_VERSION 0xff +#define UBICOM32HID_DEVICE_ID 0x49 + +#define UBICOM32HID_MAX_BRIGHTNESS_PWM 255 + +/* + * Data structure returned by the HID device + */ +struct ubicom32hid_input_data { + uint32_t ircmd; + uint8_t sw_state; + uint8_t sw_changed; +}; + +/* + * Our private data + */ +struct ubicom32hid_data { + /* + * Pointer to the platform data structure, we need the settings. + */ + const struct ubicom32hid_platform_data *pdata; + + /* + * Backlight device + */ + struct backlight_device *bldev; + + /* + * I2C client, for sending messages to the HID device + */ + struct i2c_client *client; + + /* + * Current intensity, used for get_intensity. + */ + int cur_intensity; + + /* + * Input subsystem + * We won't register an input subsystem if there are no mappings. + */ + struct input_polled_dev *poll_dev; +}; + + +/* + * ubicom32hid_set_intensity + */ +static int ubicom32hid_set_intensity(struct backlight_device *bd) +{ + struct ubicom32hid_data *ud = + (struct ubicom32hid_data *)bl_get_data(bd); + int intensity = bd->props.brightness; + int reg; + u8_t val; + int ret; + + /* + * If we're blanked the the intensity doesn't matter. + */ + if ((bd->props.power != FB_BLANK_UNBLANK) || + (bd->props.fb_blank != FB_BLANK_UNBLANK)) { + intensity = 0; + } + + /* + * Set the brightness based on the type of backlight + */ + if (ud->pdata->type == UBICOM32HID_BL_TYPE_BINARY) { + reg = UBICOM32HID_CMD_SET_BL_EN; + if (intensity) { + val = ud->pdata->invert + ? UBICOM32HID_BL_EN_LOW : UBICOM32HID_BL_EN_HI; + } else { + val = ud->pdata->invert + ? UBICOM32HID_BL_EN_HI : UBICOM32HID_BL_EN_LOW; + } + } else { + reg = UBICOM32HID_CMD_SET_PWM; + val = ud->pdata->invert + ? (UBICOM32HID_MAX_BRIGHTNESS_PWM - intensity) : + intensity; + } + + /* + * Send the command + */ + ret = i2c_smbus_write_byte_data(ud->client, reg, val); + if (ret < 0) { + dev_warn(&ud->client->dev, "Unable to write backlight err=%d\n", + ret); + return ret; + } + + ud->cur_intensity = intensity; + + return 0; +} + +/* + * ubicom32hid_get_intensity + * Return the current intensity of the backlight. + */ +static int ubicom32hid_get_intensity(struct backlight_device *bd) +{ + struct ubicom32hid_data *ud = + (struct ubicom32hid_data *)bl_get_data(bd); + + return ud->cur_intensity; +} + +/* + * ubicom32hid_verify_data + * Verify the data to see if there is any action to be taken + * + * Returns 0 if no action is to be taken, non-zero otherwise + */ +static int ubicom32hid_verify_data(struct ubicom32hid_data *ud, + struct ubicom32hid_input_data *data) +{ + uint8_t *ircmd = (uint8_t *)&(data->ircmd); + + /* + * ircmd == DEADBEEF means ir queue is empty. Since this is a + * meaningful code, that means the rest of the message is most likely + * correct, so only process the data if the switch state has changed. + */ + if (data->ircmd == 0xDEADBEEF) { + return data->sw_changed != 0; + } + + /* + * We have an ircmd which is not empty: + * Data[1] should be the complement of Data[0] + */ + if (ircmd[0] != (u8_t)~ircmd[1]) { + return 0; + } + +#ifdef UBICOM32HID_STRICT_IR_CHECK + /* + * It seems that some remote controls don't follow the NEC protocol + * properly, so only do this check if the remote does indeed follow the + * spec. Data[3] should be the complement of Data[2] + */ + if (ircmd[2] == (u8_t)~ircmd[3]) { + return 1; + } + + /* + * For non-compliant remotes, check the system code according to what + * they send. + */ + if ((ircmd[2] != UBICOM32HID_IR_SYSTEM_CODE_CHECK) || + (ircmd[3] != UBICOM32HID_IR_SYSTEM_CODE)) { + return 0; + } +#endif + + /* + * Data checks out, process + */ + return 1; +} + +/* + * ubicom32hid_poll_input + * Poll the input from the HID device. + */ +static void ubicom32hid_poll_input(struct input_polled_dev *dev) +{ + struct ubicom32hid_data *ud = (struct ubicom32hid_data *)dev->private; + const struct ubicom32hid_platform_data *pdata = ud->pdata; + struct ubicom32hid_input_data data; + struct input_dev *id = dev->input; + int i; + int sync_needed = 0; + uint8_t cmd; + int ret; + + /* + * Flush the queue + */ + cmd = UBICOM32HID_CMD_FLUSH; + ret = i2c_master_send(ud->client, &cmd, 1); + if (ret < 0) { + return; + } + + ret = i2c_smbus_read_i2c_block_data( + ud->client, UBICOM32HID_CMD_GET_IR_SWITCH, 6, (void *)&data); + if (ret < 0) { + return; + } + + /* + * Verify the data to see if there is any action to be taken + */ + if (!ubicom32hid_verify_data(ud, &data)) { + return; + } + +#ifdef DEBUG + if (ubicom32hid_debug) { + printk("Polled ircmd=%8x swstate=%2x swchanged=%2x\n", + data.ircmd, data.sw_state, data.sw_changed); + } +#endif + + /* + * Process changed switches + */ + if (data.sw_changed) { + const struct ubicom32hid_button *ub = pdata->buttons; + for (i = 0; i < pdata->nbuttons; i++, ub++) { + uint8_t mask = (1 << ub->bit); + if (!(data.sw_changed & mask)) { + continue; + } + + sync_needed = 1; + input_event(id, ub->type, ub->code, + (data.sw_state & mask) ? 1 : 0); + } + } + if (sync_needed) { + input_sync(id); + } + + /* + * Process ir codes + */ + if (data.ircmd != 0xDEADBEEF) { + const struct ubicom32hid_ir *ui = pdata->ircodes; + for (i = 0; i < pdata->nircodes; i++, ui++) { + if (ui->ir_code == data.ircmd) { + /* + * Simulate a up/down event + */ + input_event(id, ui->type, ui->code, 1); + input_sync(id); + input_event(id, ui->type, ui->code, 0); + input_sync(id); + } + } + } +} + + +/* + * Backlight ops + */ +static struct backlight_ops ubicom32hid_blops = { + .get_brightness = ubicom32hid_get_intensity, + .update_status = ubicom32hid_set_intensity, +}; + +/* + * ubicom32hid_probe + */ +static int ubicom32hid_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ubicom32hid_platform_data *pdata; + struct ubicom32hid_data *ud; + int ret; + int i; + u8 version[2]; + char buf[1]; + + pdata = client->dev.platform_data; + if (pdata == NULL) { + return -ENODEV; + } + + /* + * See if we even have a device available before allocating memory. + * + * Hard reset the device + */ + ret = gpio_request(pdata->gpio_reset, "ubicom32hid-reset"); + if (ret < 0) { + return ret; + } + gpio_direction_output(pdata->gpio_reset, pdata->gpio_reset_polarity); + udelay(100); + gpio_set_value(pdata->gpio_reset, !pdata->gpio_reset_polarity); + udelay(100); + + /* + * soft reset the device. It sometimes takes a while to do this. + */ + for (i = 0; i < 50; i++) { + buf[0] = UBICOM32HID_CMD_RESET; + ret = i2c_master_send(client, buf, 1); + if (ret > 0) { + break; + } + udelay(10000); + } + if (i == 50) { + dev_warn(&client->dev, "Unable to reset device\n"); + goto fail; + } + + ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_DEVICE_ID); + if (ret != UBICOM32HID_DEVICE_ID) { + dev_warn(&client->dev, "Incorrect device id %02x\n", buf[0]); + ret = -ENODEV; + goto fail; + } + + ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_VERSION); + if (ret < 0) { + dev_warn(&client->dev, "Unable to get version\n"); + goto fail; + } + version[0] = ret; + + ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_REVISION); + if (ret < 0) { + dev_warn(&client->dev, "Unable to get revision\n"); + goto fail; + } + version[1] = ret; + + /* + * Allocate our private data + */ + ud = kzalloc(sizeof(struct ubicom32hid_data), GFP_KERNEL); + if (!ud) { + ret = -ENOMEM; + goto fail; + } + ud->pdata = pdata; + ud->client = client; + + /* + * Register our backlight device + */ + ud->bldev = backlight_device_register(DRIVER_NAME, &client->dev, + ud, &ubicom32hid_blops); + if (IS_ERR(ud->bldev)) { + ret = PTR_ERR(ud->bldev); + goto fail2; + } + platform_set_drvdata(client, ud); + + /* + * Start up the backlight with the requested intensity + */ + ud->bldev->props.power = FB_BLANK_UNBLANK; + ud->bldev->props.max_brightness = + (pdata->type == UBICOM32HID_BL_TYPE_PWM) ? + UBICOM32HID_MAX_BRIGHTNESS_PWM : 1; + if (pdata->default_intensity < ud->bldev->props.max_brightness) { + ud->bldev->props.brightness = pdata->default_intensity; + } else { + dev_warn(&client->dev, "Default brightness out of range, " + "setting to max\n"); + ud->bldev->props.brightness = ud->bldev->props.max_brightness; + } + + ubicom32hid_set_intensity(ud->bldev); + + /* + * Check to see if we have any inputs + */ + if (!pdata->nbuttons && !pdata->nircodes) { + goto done; + } + + /* + * We have buttons or codes, we must register an input device + */ + ud->poll_dev = input_allocate_polled_device(); + if (!ud->poll_dev) { + ret = -ENOMEM; + goto fail3; + } + + /* + * Setup the polling to default to 100ms + */ + ud->poll_dev->poll = ubicom32hid_poll_input; + ud->poll_dev->poll_interval = + pdata->poll_interval ? pdata->poll_interval : 100; + ud->poll_dev->private = ud; + + ud->poll_dev->input->name = + pdata->input_name ? pdata->input_name : "Ubicom32HID"; + ud->poll_dev->input->phys = "ubicom32hid/input0"; + ud->poll_dev->input->dev.parent = &client->dev; + ud->poll_dev->input->id.bustype = BUS_I2C; + + /* + * Set the capabilities by running through the buttons and ir codes + */ + for (i = 0; i < pdata->nbuttons; i++) { + const struct ubicom32hid_button *ub = &pdata->buttons[i]; + + input_set_capability(ud->poll_dev->input, + ub->type ? ub->type : EV_KEY, ub->code); + } + + for (i = 0; i < pdata->nircodes; i++) { + const struct ubicom32hid_ir *ui = &pdata->ircodes[i]; + + input_set_capability(ud->poll_dev->input, + ui->type ? ui->type : EV_KEY, ui->code); + } + + ret = input_register_polled_device(ud->poll_dev); + if (ret) { + goto fail3; + } + +done: + printk(KERN_INFO DRIVER_NAME ": enabled, version=%02x.%02x\n", + version[0], version[1]); + + return 0; + +fail3: + gpio_free(ud->pdata->gpio_reset); + backlight_device_unregister(ud->bldev); +fail2: + kfree(ud); +fail: + gpio_free(pdata->gpio_reset); + return ret; +} + +/* + * ubicom32hid_remove + */ +static int ubicom32hid_remove(struct i2c_client *client) +{ + struct ubicom32hid_data *ud = + (struct ubicom32hid_data *)platform_get_drvdata(client); + + gpio_free(ud->pdata->gpio_reset); + + backlight_device_unregister(ud->bldev); + + if (ud->poll_dev) { + input_unregister_polled_device(ud->poll_dev); + input_free_polled_device(ud->poll_dev); + } + + platform_set_drvdata(client, NULL); + + kfree(ud); + + return 0; +} + +static struct i2c_driver ubicom32hid_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = ubicom32hid_probe, + .remove = __exit_p(ubicom32hid_remove), + .id_table = ubicom32hid_id, +}; + +/* + * ubicom32hid_init + */ +static int __init ubicom32hid_init(void) +{ + return i2c_add_driver(&ubicom32hid_driver); +} +module_init(ubicom32hid_init); + +/* + * ubicom32hid_exit + */ +static void __exit ubicom32hid_exit(void) +{ + i2c_del_driver(&ubicom32hid_driver); +} +module_exit(ubicom32hid_exit); + +MODULE_AUTHOR("Pat Tjin <@ubicom.com>") +MODULE_DESCRIPTION("Ubicom HID driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input.c new file mode 100644 index 000000000..e2e0c24d6 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input.c @@ -0,0 +1,265 @@ +/* + * arch/ubicom32/mach-common/ubicom32input.c + * Ubicom32 Input driver + * + * based on gpio-keys + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + * + * + * TODO: add groups for inputs which can be sampled together (i.e. I2C) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct ubicom32input_data { + struct ubicom32input_platform_data *pdata; + + struct input_polled_dev *poll_dev; + + /* + * collection of previous states for buttons + */ + u8 prev_state[0]; +}; + +/* + * ubicom32input_poll + */ +static void ubicom32input_poll(struct input_polled_dev *dev) +{ + struct ubicom32input_data *ud = + (struct ubicom32input_data *)dev->private; + struct ubicom32input_platform_data *pdata = ud->pdata; + struct input_dev *id = dev->input; + int i; + int sync_needed = 0; + + for (i = 0; i < pdata->nbuttons; i++) { + const struct ubicom32input_button *ub = &pdata->buttons[i]; + int state = 0; + + int val = gpio_get_value(ub->gpio); + + /* + * Check to see if the state changed from the last time we + * looked + */ + if (val == ud->prev_state[i]) { + continue; + } + + /* + * The state has changed, determine if we are "up" or "down" + */ + ud->prev_state[i] = val; + + if ((!val && ub->active_low) || (val && !ub->active_low)) { + state = 1; + } + + input_event(id, ub->type, ub->code, state); + sync_needed = 1; + } + + if (sync_needed) { + input_sync(id); + } +} + +/* + * ubicom32input_probe + */ +static int __devinit ubicom32input_probe(struct platform_device *pdev) +{ + int i; + struct ubicom32input_data *ud; + struct input_polled_dev *poll_dev; + struct input_dev *input_dev; + struct ubicom32input_platform_data *pdata; + int ret; + + pdata = pdev->dev.platform_data; + if (!pdata) { + return -EINVAL; + } + + ud = kzalloc(sizeof(struct ubicom32input_data) + + pdata->nbuttons, GFP_KERNEL); + if (!ud) { + return -ENOMEM; + } + ud->pdata = pdata; + + poll_dev = input_allocate_polled_device(); + if (!poll_dev) { + ret = -ENOMEM; + goto fail; + } + + platform_set_drvdata(pdev, ud); + + ud->poll_dev = poll_dev; + poll_dev->private = ud; + poll_dev->poll = ubicom32input_poll; + + /* + * Set the poll interval requested, default to 50 msec + */ + if (pdata->poll_interval) { + poll_dev->poll_interval = pdata->poll_interval; + } else { + poll_dev->poll_interval = 50; + } + + /* + * Setup the input device + */ + input_dev = poll_dev->input; + input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input"; + input_dev->phys = "ubicom32input/input0"; + input_dev->dev.parent = &pdev->dev; + input_dev->id.bustype = BUS_HOST; + + /* + * Reserve the GPIOs + */ + for (i = 0; i < pdata->nbuttons; i++) { + const struct ubicom32input_button *ub = &pdata->buttons[i]; + + ret = gpio_request(ub->gpio, + ub->desc ? ub->desc : "ubicom32input"); + if (ret < 0) { + pr_err("ubicom32input: failed to request " + "GPIO %d ret=%d\n", ub->gpio, ret); + goto fail2; + } + + ret = gpio_direction_input(ub->gpio); + if (ret < 0) { + pr_err("ubicom32input: failed to set " + "GPIO %d to input ret=%d\n", ub->gpio, ret); + goto fail2; + } + + /* + * Set the previous state to the non-active stae + */ + ud->prev_state[i] = ub->active_low; + + input_set_capability(input_dev, + ub->type ? ub->type : EV_KEY, ub->code); + } + + /* + * Register + */ + ret = input_register_polled_device(ud->poll_dev); + if (ret) { + goto fail2; + } + + return 0; + +fail2: + /* + * release the GPIOs we have already requested. + */ + while (--i >= 0) { + gpio_free(pdata->buttons[i].gpio); + } + +fail: + printk(KERN_ERR "Ubicom32Input: Failed to register driver %d", ret); + platform_set_drvdata(pdev, NULL); + input_free_polled_device(poll_dev); + kfree(ud); + return ret; +} + +/* + * ubicom32input_remove + */ +static int __devexit ubicom32input_remove(struct platform_device *dev) +{ + struct ubicom32input_data *ud = + (struct ubicom32input_data *)platform_get_drvdata(dev); + int i; + + /* + * Free the GPIOs + */ + for (i = 0; i < ud->pdata->nbuttons; i++) { + gpio_free(ud->pdata->buttons[i].gpio); + } + + platform_set_drvdata(dev, NULL); + input_unregister_polled_device(ud->poll_dev); + input_free_polled_device(ud->poll_dev); + + kfree(ud); + + return 0; +} + +static struct platform_driver ubicom32input_driver = { + .driver = { + .name = "ubicom32input", + .owner = THIS_MODULE, + }, + .probe = ubicom32input_probe, + .remove = __devexit_p(ubicom32input_remove), +}; + +/* + * ubicom32input_init + */ +static int __devinit ubicom32input_init(void) +{ + return platform_driver_register(&ubicom32input_driver); +} + +/* + * ubicom32input_exit + */ +static void __exit ubicom32input_exit(void) +{ + platform_driver_unregister(&ubicom32input_driver); +} + +module_init(ubicom32input_init); +module_exit(ubicom32input_exit); + +MODULE_AUTHOR("Pat Tjin "); +MODULE_DESCRIPTION("Ubicom32 Input Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ubicom32-input"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input_i2c.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input_i2c.c new file mode 100644 index 000000000..b81f1919c --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input_i2c.c @@ -0,0 +1,325 @@ +/* + * arch/ubicom32/mach-common/ubicom32input_i2c.c + * Ubicom32 Input driver for I2C + * Supports PCA953x and family + * + * We hog the I2C device, turning it all to input. + * + * Based on gpio-keys, pca953x + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include + +#include + +#define UBICOM32INPUT_I2C_REG_INPUT 0 +#define UBICOM32INPUT_I2C_REG_OUTPUT 1 +#define UBICOM32INPUT_I2C_REG_INVERT 2 +#define UBICOM32INPUT_I2C_REG_DIRECTION 3 + +static const struct i2c_device_id ubicom32input_i2c_id[] = { + { "ubicom32in_pca9534", 8, }, + { "ubicom32in_pca9535", 16, }, + { "ubicom32in_pca9536", 4, }, + { "ubicom32in_pca9537", 4, }, + { "ubicom32in_pca9538", 8, }, + { "ubicom32in_pca9539", 16, }, + { "ubicom32in_pca9554", 8, }, + { "ubicom32in_pca9555", 16, }, + { "ubicom32in_pca9557", 8, }, + { "ubicom32in_max7310", 8, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ubicom32input_i2c_id); + +struct ubicom32input_i2c_data { + struct ubicom32input_i2c_platform_data *pdata; + + struct i2c_client *client; + + struct input_polled_dev *poll_dev; + + /* + * collection of previous states for buttons + */ + uint16_t prev_state; + + uint8_t ngpios; +}; + +/* + * ubicom32input_i2c_write_reg + * writes a register to the I2C device. + */ +static int ubicom32input_i2c_write_reg(struct ubicom32input_i2c_data *ud, + int reg, uint16_t val) +{ + int ret; + + if (ud->ngpios <= 8) { + ret = i2c_smbus_write_byte_data(ud->client, reg, val); + } else { + ret = i2c_smbus_write_word_data(ud->client, reg << 1, val); + } + + if (ret < 0) { + return ret; + } + + return 0; +} + +/* + * ubicom32input_i2c_read_reg + * reads a register from the I2C device. + */ +static int ubicom32input_i2c_read_reg(struct ubicom32input_i2c_data *ud, + int reg, uint16_t *val) +{ + int ret; + + if (ud->ngpios <= 8) { + ret = i2c_smbus_read_byte_data(ud->client, reg); + } else { + ret = i2c_smbus_read_word_data(ud->client, reg); + } + + if (ret < 0) { + return ret; + } + + *val = (uint16_t)ret; + + return 0; +} + +/* + * ubicom32input_i2c_poll + */ +static void ubicom32input_i2c_poll(struct input_polled_dev *dev) +{ + struct ubicom32input_i2c_data *ud = + (struct ubicom32input_i2c_data *)dev->private; + struct ubicom32input_i2c_platform_data *pdata = ud->pdata; + struct input_dev *id = dev->input; + int i; + int sync_needed = 0; + uint16_t val; + uint16_t change_mask; + + /* + * Try to get the input status, if we fail, bail out, maybe we can do it + * next time. + */ + if (ubicom32input_i2c_read_reg(ud, UBICOM32INPUT_I2C_REG_INPUT, &val)) { + return; + } + + /* + * see if anything changed by using XOR + */ + change_mask = ud->prev_state ^ val; + ud->prev_state = val; + + for (i = 0; i < pdata->nbuttons; i++) { + const struct ubicom32input_i2c_button *ub = &pdata->buttons[i]; + uint16_t mask = 1 << ub->bit; + int state = val & mask; + + /* + * Check to see if the state changed from the last time we + * looked + */ + if (!(change_mask & mask)) { + continue; + } + input_event(id, ub->type, ub->code, state); + sync_needed = 1; + } + + if (sync_needed) { + input_sync(id); + } +} + +/* + * ubicom32input_i2c_probe + */ +static int __devinit ubicom32input_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int i; + struct ubicom32input_i2c_data *ud; + struct input_polled_dev *poll_dev; + struct input_dev *input_dev; + struct ubicom32input_i2c_platform_data *pdata; + int ret; + uint16_t invert_mask = 0; + + pdata = client->dev.platform_data; + if (!pdata) { + return -EINVAL; + } + + ud = kzalloc(sizeof(struct ubicom32input_i2c_data), GFP_KERNEL); + if (!ud) { + return -ENOMEM; + } + ud->pdata = pdata; + ud->client = client; + ud->ngpios = id->driver_data; + + poll_dev = input_allocate_polled_device(); + if (!poll_dev) { + ret = -ENOMEM; + goto fail; + } + + ud->poll_dev = poll_dev; + poll_dev->private = ud; + poll_dev->poll = ubicom32input_i2c_poll; + + /* + * Set the poll interval requested, default to 100 msec + */ + if (pdata->poll_interval) { + poll_dev->poll_interval = pdata->poll_interval; + } else { + poll_dev->poll_interval = 100; + } + + /* + * Setup the input device + */ + input_dev = poll_dev->input; + input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input I2C"; + input_dev->phys = "ubicom32input_i2c/input0"; + input_dev->dev.parent = &client->dev; + input_dev->id.bustype = BUS_I2C; + + /* + * Set the capabilities + */ + for (i = 0; i < pdata->nbuttons; i++) { + const struct ubicom32input_i2c_button *ub = &pdata->buttons[i]; + + if (ub->active_low) { + invert_mask |= (1 << ub->bit); + } + + input_set_capability(input_dev, + ub->type ? ub->type : EV_KEY, ub->code); + } + + /* + * Setup the device (all inputs) + */ + ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_DIRECTION, + 0xFFFF); + if (ret < 0) { + goto fail; + } + + ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_INVERT, + invert_mask); + if (ret < 0) { + goto fail; + } + + /* + * Register + */ + ret = input_register_polled_device(ud->poll_dev); + if (ret) { + goto fail; + } + + i2c_set_clientdata(client, ud); + + return 0; + +fail: + printk(KERN_ERR "ubicom32input_i2c: Failed to register driver %d\n", + ret); + input_free_polled_device(poll_dev); + kfree(ud); + return ret; +} + +/* + * ubicom32input_i2c_remove + */ +static int __devexit ubicom32input_i2c_remove(struct i2c_client *client) +{ + struct ubicom32input_i2c_data *ud = + (struct ubicom32input_i2c_data *)i2c_get_clientdata(client); + + i2c_set_clientdata(client, NULL); + input_unregister_polled_device(ud->poll_dev); + input_free_polled_device(ud->poll_dev); + + kfree(ud); + + return 0; +} + +static struct i2c_driver ubicom32input_i2c_driver = { + .driver = { + .name = "ubicom32input_i2c", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(ubicom32input_i2c_remove), + .id_table = ubicom32input_i2c_id, + .probe = ubicom32input_i2c_probe, +}; + +/* + * ubicom32input_i2c_init + */ +static int __devinit ubicom32input_i2c_init(void) +{ + return i2c_add_driver(&ubicom32input_i2c_driver); +} + +/* + * ubicom32input_i2c_exit + */ +static void __exit ubicom32input_i2c_exit(void) +{ + i2c_del_driver(&ubicom32input_i2c_driver); +} + +module_init(ubicom32input_i2c_init); +module_exit(ubicom32input_i2c_exit); + +MODULE_AUTHOR("Pat Tjin "); +MODULE_DESCRIPTION("Ubicom32 Input Driver I2C"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ubicom32-input"); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb.c new file mode 100644 index 000000000..e13f64054 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb.c @@ -0,0 +1,132 @@ +/* + * arch/ubicom32/mach-common/ip5k_usb.c + * Ubicom32 architecture usb support. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2007 MontaVista Software, Inc. + * Author: Kevin Hilman + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 2 of the License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "usb_tio.h" + +struct usbtionode *unode = NULL; + +static struct resource usb_resources[] = { + [0] = { + .start = RJ + 0x800, + .end = RJ + 0x1000, + .flags = IORESOURCE_MEM, + }, + [1] = { /* general IRQ */ + .start = 1, /* this is a dummy value, the real irq number is passed from kernel_setup_param */ + .flags = IORESOURCE_IRQ, + }, +}; + + +static struct musb_hdrc_eps_bits musb_eps[] = { + { "ep1_tx", 4, }, + { "ep1_rx", 4, }, + { "ep2_tx", 10, }, + { "ep2_rx", 10, }, + { "ep3_tx", 9, }, + { "ep3_rx", 9, }, + { "ep4_tx", 9, }, + { "ep4_rx", 9, }, + { "ep5_tx", 6, }, + { "ep5_rx", 6, }, +}; + +static struct musb_hdrc_config musb_config = { + .multipoint = true, + .dyn_fifo = false, + .soft_con = true, + .dma = false, + + .num_eps = 6, + .dma_channels = 0, + .ram_bits = 0, + .eps_bits = musb_eps, +}; + +static struct musb_hdrc_platform_data usb_data = { +#ifdef CONFIG_USB_MUSB_OTG + .mode = MUSB_OTG, +#else +#ifdef CONFIG_USB_MUSB_HDRC_HCD + .mode = MUSB_HOST, +#else +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + .mode = MUSB_PERIPHERAL, +#endif +#endif +#endif + .clock = NULL, + .set_clock = NULL, + .config = &musb_config, +}; + +static struct platform_device musb_device = { + .name = "musb_hdrc", + .id = 0, + .dev = { + .platform_data = &usb_data, + .dma_mask = NULL, + .coherent_dma_mask = 0, + }, + .resource = usb_resources, + .num_resources = ARRAY_SIZE(usb_resources), +}; + +struct usbtio_node *usb_node = NULL; +void ubi32_usb_init(void) +{ + /* + * See if the usbtio is in the device tree. + */ + usb_node = (struct usbtio_node *)devtree_find_node("usbtio"); + if (!usb_node) { + printk(KERN_WARNING "usb init failed\n"); + return; + } + + usb_resources[1].start = usb_node->dn.recvirq; + if (platform_device_register(&musb_device) < 0) { + printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n"); + return; + } +} + +void ubi32_usb_int_clr(void) +{ + UBICOM32_IO_PORT(RJ)->int_clr = (1 << 3); +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.c new file mode 100644 index 000000000..95ace6db7 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.c @@ -0,0 +1,356 @@ +/* + * arch/ubicom32/mach-common/usb_tio.c + * Linux side Ubicom USB TIO driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include "usb_tio.h" + +#ifdef CONFIG_SMP +static DEFINE_SPINLOCK(tio_lock); +#define USB_TIO_LOCK(lock, flag) spin_lock_irqsave(lock, flag) +#define USB_TIO_UNLOCK(lock, flag) spin_unlock_irqrestore(lock, flag) +#define USB_TIO_LOCK_ISLOCKED(lock) spin_try_lock(lock) +#else +#define USB_TIO_LOCK(lock, flag) local_irq_save(flag) +#define USB_TIO_UNLOCK(lock, flag) local_irq_restore(flag) +#endif + +spinlock_t usb_tio_lock; + +/* + * usb_tio_set_hrt_interrupt() + */ +static inline void usb_tio_set_hrt_interrupt(void) +{ + ubicom32_set_interrupt(usb_node->dn.sendirq); +} + +static inline void usb_tio_wait_hrt(void) +{ + while (unlikely(usb_node->pdesc)); +} + +#if defined(USB_TIO_DEBUG) +static void usb_tio_request_verify_magic(volatile struct usb_tio_request *req) +{ + BUG_ON(req->magic != USB_TIO_REQUEST_MAGIC2); +} + +static void usb_tio_request_clear_magic(volatile struct usb_tio_request *req) +{ + req->magic = 0; +} +#endif + +static void usb_tio_request_set_magic(volatile struct usb_tio_request *req) +{ + req->magic = USB_TIO_REQUEST_MAGIC1; +} + +/* + * usb_tio_commit_request() + */ +static inline void usb_tio_commit_request(volatile struct usb_tio_request *request) +{ + wmb(); + usb_node->pdesc = request; + + /* + * next thing to do is alway checking if (usb_node->pdesc == NULL) + * to see if the request is done, so add a mb() here + */ + mb(); + usb_tio_set_hrt_interrupt(); +} + +/* + * usb_tio_read_u16() + * Synchronously read 16 bits. + */ +u8_t usb_tio_read_u16(u32_t address, u16_t *data) +{ + volatile struct usb_tio_request *tio_req = &usb_node->request; + unsigned long flag; + + /* + * Wait for any previous request to complete and then make this request. + */ + USB_TIO_LOCK(&tio_lock, flag); + usb_tio_wait_hrt(); + + /* + * Fill in the request. + */ + tio_req->address = address; + tio_req->cmd = USB_TIO_READ16_SYNC; + USB_TIO_REQUEST_SET_MAGIC(tio_req); + usb_tio_commit_request(tio_req); + + /* + * Wait for the result to show up. + */ + usb_tio_wait_hrt(); + USB_TIO_REQUEST_VERIFY_MAGIC(tio_req); + *data = (u16_t)tio_req->data; + USB_TIO_REQUEST_CLEAR_MAGIC(tio_req); + USB_TIO_UNLOCK(&tio_lock, flag); + return USB_TIO_OK; +} + +/* + * usb_tio_read_u8() + * Synchronously read 16 bits. + */ +u8_t usb_tio_read_u8(u32_t address, u8_t *data) +{ + volatile struct usb_tio_request *tio_req = &usb_node->request; + unsigned long flag; + + /* + * Wait for any previous request to complete and then make this request. + */ + USB_TIO_LOCK(&tio_lock, flag); + usb_tio_wait_hrt(); + + /* + * Fill in the request. + */ + tio_req->address = address; + tio_req->cmd = USB_TIO_READ8_SYNC; + USB_TIO_REQUEST_SET_MAGIC(tio_req); + + /* + * commit the request + */ + usb_tio_commit_request(tio_req); + + /* + * Wait for the result to show up. + */ + usb_tio_wait_hrt(); + USB_TIO_REQUEST_VERIFY_MAGIC(tio_req); + *data = (u8_t)tio_req->data; + USB_TIO_REQUEST_CLEAR_MAGIC(tio_req); + USB_TIO_UNLOCK(&tio_lock, flag); + return USB_TIO_OK; +} + +/* + * usb_tio_write_u16() + * Asynchronously write 16 bits. + */ +u8_t usb_tio_write_u16(u32_t address, u16_t data) +{ + volatile struct usb_tio_request *tio_req = &usb_node->request; + unsigned long flag; + + /* + * Wait for any previous write or pending read to complete. + */ + USB_TIO_LOCK(&tio_lock, flag); + usb_tio_wait_hrt(); + + tio_req->address = address; + tio_req->data = data; + tio_req->cmd = USB_TIO_WRITE16_ASYNC; + USB_TIO_REQUEST_SET_MAGIC(tio_req); + + /* + * commit the request + */ + usb_tio_commit_request(tio_req); + USB_TIO_UNLOCK(&tio_lock, flag); + return USB_TIO_OK; +} + +/* + * usb_tio_write_u8() + * Asynchronously write 8 bits. + */ +u8_t usb_tio_write_u8(u32_t address, u8_t data) +{ + volatile struct usb_tio_request *tio_req = &usb_node->request; + unsigned long flag; + + /* + * Wait for any previous write or pending read to complete. + */ + USB_TIO_LOCK(&tio_lock, flag); + usb_tio_wait_hrt(); + + tio_req->address = address; + tio_req->data = data; + tio_req->cmd = USB_TIO_WRITE8_ASYNC; + USB_TIO_REQUEST_SET_MAGIC(tio_req); + + /* + * commit the request + */ + usb_tio_commit_request(tio_req); + USB_TIO_UNLOCK(&tio_lock, flag); + return USB_TIO_OK; +} + +/* + * usb_tio_read_fifo() + * Synchronously read FIFO. + */ +u8_t usb_tio_read_fifo(u32_t address, u32_t buffer, u32_t bytes) +{ + volatile struct usb_tio_request *tio_req = &usb_node->request; + unsigned long flag; + + /* + * Wait for any previous request to complete and then make this request. + */ + USB_TIO_LOCK(&tio_lock, flag); + usb_tio_wait_hrt(); + + /* + * Fill in the request. + */ + tio_req->address = address; + tio_req->cmd = USB_TIO_READ_FIFO_SYNC; + tio_req->buffer = buffer; + tio_req->transfer_length = bytes; + USB_TIO_REQUEST_SET_MAGIC(tio_req); + + /* + * commit the request + */ + usb_tio_commit_request(tio_req); + + /* + * Wait for the result to show up. + */ + usb_tio_wait_hrt(); + USB_TIO_REQUEST_VERIFY_MAGIC(tio_req); + USB_TIO_REQUEST_CLEAR_MAGIC(tio_req); + USB_TIO_UNLOCK(&tio_lock, flag); + return USB_TIO_OK; +} + +/* + * usb_tio_write_fifo() + * Synchronously write 32 bits. + */ +u8_t usb_tio_write_fifo(u32_t address, u32_t buffer, u32_t bytes) +{ + volatile struct usb_tio_request *tio_req = &usb_node->request; + unsigned long flag; + + USB_TIO_LOCK(&tio_lock, flag); + usb_tio_wait_hrt(); + + tio_req->address = address; + tio_req->buffer = buffer; + tio_req->cmd = USB_TIO_WRITE_FIFO_SYNC; + tio_req->transfer_length = bytes; + USB_TIO_REQUEST_SET_MAGIC(tio_req); + /* + * commit the request + */ + usb_tio_commit_request(tio_req); + + /* + * Wait for the result to show up. + */ + usb_tio_wait_hrt(); + USB_TIO_REQUEST_VERIFY_MAGIC(tio_req); + USB_TIO_REQUEST_CLEAR_MAGIC(tio_req); + USB_TIO_UNLOCK(&tio_lock, flag); + return USB_TIO_OK; +} + +/* + * usb_tio_write_fifo_async() + * Asynchronously write 32 bits. + */ +u8_t usb_tio_write_fifo_async(u32_t address, u32_t buffer, u32_t bytes) +{ + volatile struct usb_tio_request *tio_req = &usb_node->request; + unsigned long flag; + + USB_TIO_LOCK(&tio_lock, flag); + usb_tio_wait_hrt(); + + tio_req->address = address; + + /* + * Is it necessary to make a local copy of the buffer? Any chance the URB is aborted before TIO finished the FIFO write? + */ + tio_req->buffer = buffer; + tio_req->cmd = USB_TIO_WRITE_FIFO_SYNC; + tio_req->transfer_length = bytes; + USB_TIO_REQUEST_SET_MAGIC(tio_req); + /* + * commit the request + */ + usb_tio_commit_request(tio_req); + USB_TIO_UNLOCK(&tio_lock, flag); + return USB_TIO_OK; +} + +/* + * usb_tio_read_int_status() + * read and clear the interrupt status registers + */ +void usb_tio_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx) +{ + + /* + * clear the interrupt must be syncronized with the TIO thread to prevent the racing condiiton + * that TIO thread try to set it at same time + */ + asm volatile ( + "1: bset (%0), (%0), #0 \n\t" \ + " jmpne.f 1b \n\t" \ + : + : "a" (&usb_node->usb_vp_control) + : "memory", "cc" + ); + + *int_usb = usb_node->usb_vp_hw_int_usb; + *int_tx = cpu_to_le16(usb_node->usb_vp_hw_int_tx); + *int_rx = cpu_to_le16(usb_node->usb_vp_hw_int_rx); + + //printk(KERN_INFO "int read %x, %x, %x\n", *int_usb, *int_tx, *int_rx); + + /* + * The interrupt status register is read-clean, so clear it now + */ + usb_node->usb_vp_hw_int_usb = 0; + usb_node->usb_vp_hw_int_tx = 0; + usb_node->usb_vp_hw_int_rx = 0; + + /* + * release the lock bit + */ + usb_node->usb_vp_control &= 0xfffe; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.h new file mode 100644 index 000000000..a88ea18d5 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.h @@ -0,0 +1,111 @@ +/* + * arch/ubicom32/mach-common/usb_tio.h + * Definitions for usb_tio.c + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef _USB_TIO_H +#define _USB_TIO_H + +#undef USB_TIO_DEBUG + +#define USB_TIO_REQUEST_MAGIC1 0x2307 +#define USB_TIO_REQUEST_MAGIC2 0x0789 +#if defined(USB_TIO_DEBUG) +#define USB_TIO_REQUEST_VERIFY_MAGIC(req) usb_tio_request_verify_magic(req) +#define USB_TIO_REQUEST_SET_MAGIC(req) usb_tio_request_set_magic(req) +#define USB_TIO_REQUEST_CLEAR_MAGIC(req) usb_tio_request_clear_magic(req) +#else +#define USB_TIO_REQUEST_VERIFY_MAGIC(req) +#define USB_TIO_REQUEST_SET_MAGIC(req) usb_tio_request_set_magic(req) +#define USB_TIO_REQUEST_CLEAR_MAGIC(req) +#endif + +enum USB_TIO_status { + USB_TIO_OK, + USB_TIO_ERROR, + USB_TIO_ERROR_COMMIT, +}; + +enum USB_TIO_cmds { + USB_TIO_READ16_SYNC, + USB_TIO_READ8_SYNC, + USB_TIO_READ_FIFO_SYNC, + + USB_TIO_WRITE16_ASYNC, + USB_TIO_WRITE8_ASYNC, + USB_TIO_WRITE_FIFO_ASYNC, + + USB_TIO_WRITE16_SYNC, + USB_TIO_WRITE8_SYNC, + USB_TIO_WRITE_FIFO_SYNC, + +}; + +enum USB_TIO_state { + USB_TIO_NORMAL, + USB_TIO_DMA_SETUP, +}; + +struct usb_tio_request { + volatile u32_t address; + union { + volatile u32_t data; + volatile u32_t buffer; + }; + volatile u16_t cmd; + const volatile u16_t status; + volatile u32_t transfer_length; + volatile u32_t thread_mask; + volatile u16_t magic; +}; + +struct usbtio_node { + struct devtree_node dn; + volatile struct usb_tio_request * volatile pdesc; + struct usb_tio_request request; + volatile u32_t usb_vp_config; + volatile u32_t usb_vp_control; + const volatile u32_t usb_vp_status; + volatile u16_t usb_vp_hw_int_tx; + volatile u16_t usb_vp_hw_int_rx; + volatile u8_t usb_vp_hw_int_usb; + volatile u8_t usb_vp_hw_int_mask_usb; + volatile u16_t usb_vp_hw_int_mask_tx; + volatile u16_t usb_vp_hw_int_mask_rx; + +}; + +extern struct usbtio_node *usb_node; +extern void ubi32_usb_init(void); +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/vdc_tio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/vdc_tio.c new file mode 100644 index 000000000..cde0cb20f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-common/vdc_tio.c @@ -0,0 +1,111 @@ +/* + * arch/ubicom32/mach-common/vdc_tio.c + * Generic initialization for VDC + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include + +#include +#include + +/* + * Resources that this driver uses + */ +static struct resource vdc_tio_resources[] = { + /* + * Send IRQ + */ + [0] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Receive IRQ (optional) + */ + [1] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Memory Mapped Registers + */ + [2] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_MEM, + }, +}; + +/* + * The platform_device structure which is passed to the driver + */ +static struct platform_device vdc_tio_platform_device = { + .name = "ubicom32fb", + .id = -1, + .resource = vdc_tio_resources, + .num_resources = ARRAY_SIZE(vdc_tio_resources), +}; + +/* + * vdc_tio_init + * Checks the device tree and instantiates the driver if found + */ +void __init vdc_tio_init(void) +{ + /* + * Check the device tree for the vdc_tio + */ + struct vdc_tio_node *vdc_node = + (struct vdc_tio_node *)devtree_find_node("vdctio"); + if (!vdc_node) { + printk(KERN_WARNING "No vdc_tio found\n"); + return; + } + + /* + * Fill in the resources and platform data from devtree information + */ + vdc_tio_resources[0].start = vdc_node->dn.sendirq; + vdc_tio_resources[1].start = vdc_node->dn.recvirq; + vdc_tio_resources[2].start = (u32_t)vdc_node->regs; + vdc_tio_resources[2].end = (u32_t)vdc_node->regs + + sizeof(struct vdc_tio_vp_regs); + + /* + * Try to get the device registered + */ + if (platform_device_register(&vdc_tio_platform_device) < 0) { + printk(KERN_WARNING "VDC failed to register\n"); + } +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Kconfig b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Kconfig new file mode 100644 index 000000000..b53d23965 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Kconfig @@ -0,0 +1,28 @@ + +config IP5170DPF + bool "IP5170DPF" + select UBICOM32_V3 + select I2C + select I2C_GPIO + select FB + select FB_UBICOM32 + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE + select UBICOM_HID + select NEW_LEDS + select LEDS_CLASS + select LEDS_GPIO + help + IP5170 Digital Picture Frame board, 8005-1113, IP5K-BEV-0011-13 v1.3 + +config IP5160DEV + bool "IP5160Dev_Ver1Dot1" + select UBICOM32_V3 + help + Ubicom StreamEngine 5000 Development Board, IP5K-BDV-0004-11 v1.1 + +config IP5160EVAL + bool "IP5160RGWEval_Ver2Rev2" + select UBICOM32_V3 + help + Ubicom StreamEngine 5000 RGW Evaluation Board, IP5K-RGW-0004-11 v2.2 diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Makefile b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Makefile new file mode 100644 index 000000000..d02f339bd --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Makefile @@ -0,0 +1,31 @@ +# +# arch/ubicom32/mach-ip5k/Makefile +# Makefile for boards which have an ip5k on them. +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# + +obj-$(CONFIG_IP5170DPF) += board-ip5170dpf.o +obj-$(CONFIG_IP5160DEV) += board-ip5160dev.o +obj-$(CONFIG_IP5160EVAL) += board-ip5160rgw.o diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160dev.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160dev.c new file mode 100644 index 000000000..4fb130d51 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160dev.c @@ -0,0 +1,109 @@ +/* + * arch/ubicom32/mach-ip5k/board-ip5160dev.c + * Platform initialization for ip5160dev board. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include + +#include +#include +#ifdef CONFIG_SERIAL_UBI32_SERDES +#include +#endif + +/* + * Factory Default Button on the board at PXn + * TODO: This is just a placeholder and it needs to include proper header files + */ +struct ubicom32fdb_platform_data { + int fdb_gpio; + bool fdb_polarity; +}; + +static struct ubicom32fdb_platform_data ip5160dev_fdb_data = { + .fdb_gpio = 0, + .fdb_polarity = true, +}; + +static struct platform_device ip5160dev_fdb_device = { + .name = "ubicom32fdb", + .id = -1, + .dev = { + .platform_data = &ip5160dev_fdb_data, + }, +}; + +#ifdef CONFIG_SERIAL_UBI32_SERDES +static struct resource ip5160dev_ubicom32_suart_resources[] = { + { + .start = RD, + .end = RD, + .flags = IORESOURCE_MEM, + }, + { + .start = PORT_OTHER_INT(RD), + .end = PORT_OTHER_INT(RD), + .flags = IORESOURCE_IRQ, + }, + { + .start = 240000000, + .end = 240000000, + .flags = UBICOM32_SUART_IORESOURCE_CLOCK, + }, +}; + +static struct platform_device ip5160dev_ubicom32_suart_device = { + .name = "ubicom32suart", + .id = -1, + .num_resources = ARRAY_SIZE(ip5160dev_ubicom32_suart_resources), + .resource = ip5160dev_ubicom32_suart_resources, +}; +#endif + +/* + * List of all devices in our system + */ +static struct platform_device *ip5160dev_devices[] __initdata = { +#ifdef CONFIG_SERIAL_UBI32_SERDES + &ip5160dev_ubicom32_suart_device, +#endif + &ip5160dev_fdb_device, +}; + +/* + * ip5160dev_init + * Called to add the devices which we have on this board + */ +static int __init ip5160dev_init(void) +{ + ubi_gpio_init(); + printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); + platform_add_devices(ip5160dev_devices, ARRAY_SIZE(ip5160dev_devices)); + return 0; +} + +arch_initcall(ip5160dev_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160rgw.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160rgw.c new file mode 100644 index 000000000..fb928f79d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160rgw.c @@ -0,0 +1,75 @@ +/* + * arch/ubicom32/mach-ip5k/board-ip5160rgw.c + * Platform initialization for ip5160rgw board. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include + +/* + * Factory Default Button on the board at PXn + * TODO: This is just a placeholder and it needs to include proper header files + */ +struct ubicom32fdb_platform_data { + int fdb_gpio; + bool fdb_polarity; +}; + +static struct ubicom32fdb_platform_data ip5160rgw_fdb_data = { + .fdb_gpio = 0, + .fdb_polarity = true, +}; + +static struct platform_device ip5160rgw_fdb_device = { + .name = "ubicom32fdb", + .id = -1, + .dev = { + .platform_data = &ip5160rgw_fdb_data, + }, +}; + +/* + * List of all devices in our system + */ +static struct platform_device *ip5160rgw_devices[] __initdata = { + &ip5160rgw_fdb_device, +}; + +/* + * ip5160rgw_init + * Called to add the devices which we have on this board + */ +static int __init ip5160rgw_init(void) +{ + ubi_gpio_init(); + printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); + platform_add_devices(ip5160rgw_devices, ARRAY_SIZE(ip5160rgw_devices)); + return 0; +} + +arch_initcall(ip5160rgw_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5170dpf.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5170dpf.c new file mode 100644 index 000000000..ef04dcaa8 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5170dpf.c @@ -0,0 +1,279 @@ +/* + * arch/ubicom32/mach-ip5k/board-ip5170dpf.c + * Platform initialization for ip5160dpf board. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +/* + * LEDs + * + * WLAN PD9 (Note this is shared with MISO, but we don't use it) + * WPS PD8 + * + * TODO: check triggers, are they generic? + */ +static struct gpio_led ip5170dpf_gpio_leds[] = { + { + .name = "d31:green:WLAN1", + .default_trigger = "WLAN1", + .gpio = GPIO_RD_9, + .active_low = 1, + }, + { + .name = "d30:green:WPS", + .default_trigger = "WPS", + .gpio = GPIO_RD_8, + .active_low = 1, + }, +}; + +static struct gpio_led_platform_data ip5170dpf_gpio_led_platform_data = { + .num_leds = 2, + .leds = ip5170dpf_gpio_leds, +}; + +static struct platform_device ip5170dpf_gpio_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &ip5170dpf_gpio_led_platform_data, + }, +}; + +/* + * Backlight on the board PD0, hardware PWM + */ +static const struct ubicom32hid_button ip5170dpf_ubicom32hid_buttons[] = { + { + .type = EV_KEY, + .code = KEY_UP, + .bit = 0, + }, + { + .type = EV_KEY, + .code = KEY_LEFT, + .bit = 1, + }, + { + .type = EV_KEY, + .code = KEY_RIGHT, + .bit = 2, + }, + { + .type = EV_KEY, + .code = KEY_DOWN, + .bit = 3, + }, + { + .type = EV_KEY, + .code = KEY_ENTER, + .bit = 4, + }, + { + .type = EV_KEY, + .code = KEY_MENU, + .bit = 5, + }, + { + .type = EV_KEY, + .code = KEY_ESC, + .bit = 7, + }, +}; + +static const struct ubicom32hid_ir ip5170dpf_ubicom32hid_ircodes[] = { + { + .type = EV_KEY, + .code = KEY_UP, + .ir_code = 0xF807916E + }, + { + .type = EV_KEY, + .code = KEY_DOWN, + .ir_code = 0xF20D916E + }, + { + .type = EV_KEY, + .code = KEY_LEFT, + .ir_code = 0xF609916E + }, + { + .type = EV_KEY, + .code = KEY_RIGHT, + .ir_code = 0xF40B916E + }, + { + .type = EV_KEY, + .code = KEY_ENTER, + .ir_code = 0xF50A916E + }, + { /* rotate */ + .type = EV_KEY, + .code = KEY_FN_F1, + .ir_code = 0xF906916E + }, + { + .type = EV_KEY, + .code = KEY_MENU, + .ir_code = 0xF708916E + }, + { /* font size */ + .type = EV_KEY, + .code = KEY_FN_F2, + .ir_code = 0xF30C916E + }, + { + .type = EV_KEY, + .code = KEY_ESC, + .ir_code = 0xF10E916E + }, + { + .type = EV_KEY, + .code = KEY_VOLUMEUP, + .ir_code = 0xF00F916E + }, + { + .type = EV_KEY, + .code = KEY_VOLUMEDOWN, + .ir_code = 0xED12916E + }, + { + .type = EV_KEY, + .code = KEY_MUTE, + .ir_code = 0xEA15916E + }, + { + .type = EV_KEY, + .code = KEY_INFO, + .ir_code = 0xEF10916E + }, + { /* Like */ + .type = EV_KEY, + .code = KEY_FN_F3, + .ir_code = 0xEE11916E + }, + { /* Dislike */ + .type = EV_KEY, + .code = KEY_FN_F4, + .ir_code = 0xEB14916E + }, + { + .type = EV_KEY, + .code = KEY_POWER, + .ir_code = 0xFD02916E + }, +}; + +static struct ubicom32hid_platform_data ip5170dpf_ubicom32hid_platform_data = { + .gpio_reset = GPIO_RA_4, + .gpio_reset_polarity = 0, + .type = UBICOM32HID_BL_TYPE_BINARY, + .invert = 0, + .default_intensity = 1, + .buttons = ip5170dpf_ubicom32hid_buttons, + .nbuttons = ARRAY_SIZE(ip5170dpf_ubicom32hid_buttons), + .ircodes = ip5170dpf_ubicom32hid_ircodes, + .nircodes = ARRAY_SIZE(ip5170dpf_ubicom32hid_ircodes), +}; + +/* + * Devices on the I2C bus + */ +static struct i2c_board_info __initdata ip5170dpf_i2c_board_info[] = { + /* + * U24, ubicom32hid + */ + { + .type = "ubicom32hid", + .addr = 0x08, + .platform_data = &ip5170dpf_ubicom32hid_platform_data, + }, + + /* + * U14, CS4350 DAC, address 0x4B + */ +}; + +/* + * I2C bus on the board, SDA PF13, SCL PF14 + */ +static struct i2c_gpio_platform_data ip5170dpf_i2c_data = { + .sda_pin = GPIO_RF_13, + .scl_pin = GPIO_RF_14, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 1, + .udelay = 5, +}; + +static struct platform_device ip5170dpf_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ip5170dpf_i2c_data, + }, +}; + +/* + * List of all devices in our system + */ +static struct platform_device *ip5170dpf_devices[] __initdata = { + &ip5170dpf_i2c_device, + &ip5170dpf_gpio_leds_device, +}; + +/* + * ip5170dpf_init + * Called to add the devices which we have on this board + */ +static int __init ip5170dpf_init(void) +{ + ubi_gpio_init(); + + vdc_tio_init(); + + printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); + platform_add_devices(ip5170dpf_devices, ARRAY_SIZE(ip5170dpf_devices)); + + printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); + i2c_register_board_info(0, ip5170dpf_i2c_board_info, ARRAY_SIZE(ip5170dpf_i2c_board_info)); + + return 0; +} + +arch_initcall(ip5170dpf_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Kconfig b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Kconfig new file mode 100644 index 000000000..8a7f2f1cf --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Kconfig @@ -0,0 +1,205 @@ +config IP7145DPF + bool "IP7145DPF" + select UBICOM32_V4 + select UBICOM_INPUT + select UBICOM_INPUT_I2C + select RTC_CLASS + select RTC_DRV_S35390A + select I2C + select I2C_GPIO + select GPIO_PCA953X + select FB + select FB_UBICOM32 + select LCD_CLASS_DEVICE + select LCD_UBICOM32POWER + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE + select BACKLIGHT_UBICOM32 + select SND_UBI32 + select MMC_UBICOM32 + select MMC + select MMC_BLOCK + help + IP7145 Digital Picture Frame reference design, supports: + 8007-0410 v1.0 + +config IP7160RGW + bool "IP7160RGW" + select UBICOM32_V4 + select UBICOM_INPUT + select NEW_LEDS + select LEDS_CLASS + select LEDS_GPIO + select SPI + select SPI_UBICOM32_GPIO + select VLAN_8021Q + select UBICOM_SWITCH + select UBICOM_SWITCH_BCM539X + help + Ubicom IP7160 RGW Eval, supports: + 8007-0110 v1.0 + 8007-0111 v1.1 + 8007-0112 v1.2 + +config IP7160RGWLCD + bool "IP7160RGWLCD" + select UBICOM32_V4 + select UBICOM_INPUT + select NEW_LEDS + select LEDS_CLASS + select LEDS_GPIO + select SPI + select SPI_UBICOM32_GPIO + select VLAN_8021Q + select UBICOM_SWITCH + select UBICOM_SWITCH_BCM539X + select INPUT_TOUCHSCREEN + select TOUCHSCREEN_TSC2007 + select FB + select FB_UBICOM32_VIRTUAL + select I2C + select I2C_GPIO + help + Ubicom IP7160 RGW Eval, supports: + 8007-0112 v1.2 + 8007-1410 v1.0 + + With Ubicom LCD Adapter + 8007-0920 v2.0 + 8007-0921 v2.1 + + +config IP7160BRINGUP + bool "IP7160BRINGUP" + select UBICOM32_V4 + select NEW_LEDS + select LEDS_CLASS + select LEDS_GPIO + help + Ubicom IP7160 Bringup, supports: + 8007-0010 v1.0 + +config IP7160DPF + bool "IP7160DPF" + select UBICOM32_V4 + select I2C + select I2C_GPIO + select FB + select FB_UBICOM32 + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE + select SND_UBI32 + select SND_UBI32_AUDIO_CS4350 + select UBICOM_HID + help + IP7160 Digital Picture Frame board, supports: + 8007-0211 Rev 1.1 + +config IP7500MODULE + bool "IP7500MODULE" + select UBICOM32_V4 + help + Ubicom IP7500 CPU Module board, supports: + 8007-0510 v1.0 + 8007-0510A v1.0 + + Please see ip7500module.c for more details. + +config IP7500AV + bool "IP7500AV" + select UBICOM32_V4 + select I2C + select I2C_GPIO + select SND_UBI32 + select SND_UBI32_AUDIO_CS4384 + select FB + select FB_UBICOM32 + help + Ubicom IP7500 Audio Video board, supports: + 8007-0810 v1.0 + + With Ubicom IP7500 CPU Module board: + 8007-0510 v1.0 -or- + 8007-0510A v1.0 + + Please see ip7500av.c for more details. + +config IP7500MEDIA + bool "IP7500MEDIA" + select UBICOM32_V4 + select UBICOM_INPUT_I2C + select RTC_CLASS + select RTC_DRV_S35390A + select I2C + select I2C_GPIO + select GPIO_PCA953X + select FB + select FB_UBICOM32 + select FB_UBICOM32_VIRTUAL + select FB_UBICOM32_VIRTUAL_NOAUTO + select LCD_CLASS_DEVICE + select LCD_UBICOM32POWER + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE + select BACKLIGHT_UBICOM32 + select INPUT_TOUCHSCREEN + select TOUCHSCREEN_TSC2007 + select SOUND + select SND + select SND_UBI32 + select SND_UBI32_AUDIO_CS4350 + select MMC_UBICOM32 + select MMC + select MMC_BLOCK + help + IP7500 Media Board w/ IP7500 CPU Module board, supports: + 8007-0610 v1.0 w/ 8007-0510 v1.0 + 8007-0610 v1.0 w/ 8007-0510 v1.0 NOPHY + 8007-0610 v1.0 w/ 8007-0511 v1.1 NOPHY + + Also supports optional LCD Adapter board: + 8006-0920 v2.0 + 8006-0921 v2.1 + + Please see ip7500media.c for more details. + +config IP7500WSPKR + bool "IP7500WSPKR" + select UBICOM32_V4 + select I2C + select I2C_GPIO + select SOUND + select SND + select SND_UBI32 + select SND_UBI32_AUDIO_CS4350 + help + IP7500 Wireless Speaker Board, supports: + 8007-1210 v1.0 + + Please see ip7500wspkr.c for more details. + +config IP7500IAP + bool "IP7500IAP" + select UBICOM32_V4 + select I2C + select I2C_GPIO + select FB + select FB_UBICOM32_VIRTUAL + select SOUND + select SND + select SND_UBI32 + select SND_UBI32_AUDIO_CS4350 + select RTC_CLASS + select RTC_DRV_S35390A + select INPUT_TOUCHSCREEN + select TOUCHSCREEN_TSC2007 + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE + select BACKLIGHT_UBICOM32 + help + IP7500 Internet Audio Player, supports: + 8007-1110 v1.0 + + Please see ip7500iap.c for more details. + + + Please see ip7500media.c for more details. diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Makefile b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Makefile new file mode 100644 index 000000000..f9df397ee --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Makefile @@ -0,0 +1,38 @@ +# +# arch/ubicom32/mach-ip7k/Makefile +# Makefile for ip7k based boards. +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# + +obj-$(CONFIG_IP7145DPF) += board-ip7145dpf.o +obj-$(CONFIG_IP7160RGW) += board-ip7160rgw.o +obj-$(CONFIG_IP7160RGWLCD) += board-ip7160rgw.o +obj-$(CONFIG_IP7160BRINGUP) += board-ip7160bringup.o +obj-$(CONFIG_IP7160DPF) += board-ip7160dpf.o +obj-$(CONFIG_IP7500MODULE) += board-ip7500module.o +obj-$(CONFIG_IP7500MEDIA) += board-ip7500media.o +obj-$(CONFIG_IP7500AV) += board-ip7500av.o +obj-$(CONFIG_IP7500WSPKR) += board-ip7500wspkr.o +obj-$(CONFIG_IP7500IAP) += board-ip7500iap.o diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7145dpf.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7145dpf.c new file mode 100644 index 000000000..d3348d30f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7145dpf.c @@ -0,0 +1,715 @@ +/* + * arch/ubicom32/mach-ip7k/board-ip7145dpf.c + * Board file for IP7145DPF, rev 1.0, P/N 8007-0410 + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/****************************************************************************** + * SD/IO Port F (Slot 1) platform data + */ +static struct resource ip7145dpf_portf_sd_resources[] = { + /* + * Send IRQ + */ + [0] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Receive IRQ + */ + [1] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Memory Mapped Registers + */ + [2] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct ubicom32sd_card ip7145dpf_portf_sd_cards[] = { + [0] = { + .pin_wp = IP7145DPF_IOB0, + .wp_polarity = 1, + .pin_pwr = IP7145DPF_IOB4, + .pin_cd = GPIO_RA_4, + }, + [1] = { + .pin_wp = IP7145DPF_IOB1, + .wp_polarity = 1, + .pin_pwr = IP7145DPF_IOB5, + .pin_cd = GPIO_RA_6, + }, +}; + +static struct ubicom32sd_platform_data ip7145dpf_portf_sd_platform_data = { + .ncards = 2, + .cards = ip7145dpf_portf_sd_cards, +}; + +static struct platform_device ip7145dpf_portf_sd_device = { + .name = "ubicom32sd", + .id = 0, + .resource = ip7145dpf_portf_sd_resources, + .num_resources = ARRAY_SIZE(ip7145dpf_portf_sd_resources), + .dev = { + .platform_data = &ip7145dpf_portf_sd_platform_data, + }, + +}; + +/* + * ip7145dpf_portf_sd_init + */ +static void ip7145dpf_portf_sd_init(void) +{ + /* + * Check the device tree for the sd_tio + */ + struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd"); + if (!sd_node) { + printk(KERN_INFO "PortF SDTIO not found\n"); + return; + } + + /* + * Fill in the resources and platform data from devtree information + */ + ip7145dpf_portf_sd_resources[0].start = sd_node->dn.sendirq; + ip7145dpf_portf_sd_resources[1].start = sd_node->dn.recvirq; + ip7145dpf_portf_sd_resources[2].start = (u32_t)&(sd_node->regs); + ip7145dpf_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); + + platform_device_register(&ip7145dpf_portf_sd_device); +} + +/****************************************************************************** + * SD/IO Port B (Slot 2) platform data + */ +static struct resource ip7145dpf_portb_sd_resources[] = { + /* + * Send IRQ + */ + [0] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Receive IRQ + */ + [1] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Memory Mapped Registers + */ + [2] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct ubicom32sd_card ip7145dpf_portb_sd_cards[] = { + [0] = { + .pin_wp = IP7145DPF_IOB2, + .wp_polarity = 1, + .pin_pwr = IP7145DPF_IOB6, + .pin_cd = IP7145DPF_IOB3, + }, +}; + +static struct ubicom32sd_platform_data ip7145dpf_portb_sd_platform_data = { + .ncards = 1, + .cards = ip7145dpf_portb_sd_cards, +}; + +static struct platform_device ip7145dpf_portb_sd_device = { + .name = "ubicom32sd", + .id = 1, + .resource = ip7145dpf_portb_sd_resources, + .num_resources = ARRAY_SIZE(ip7145dpf_portb_sd_resources), + .dev = { + .platform_data = &ip7145dpf_portb_sd_platform_data, + }, + +}; + +/* + * ip7145dpf_portb_sd_init + */ +static void ip7145dpf_portb_sd_init(void) +{ + /* + * Check the device tree for the sd_tio + */ + struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd"); + if (!sd_node) { + printk(KERN_INFO "PortB SDTIO not found\n"); + return; + } + + /* + * Fill in the resources and platform data from devtree information + */ + ip7145dpf_portb_sd_resources[0].start = sd_node->dn.sendirq; + ip7145dpf_portb_sd_resources[1].start = sd_node->dn.recvirq; + ip7145dpf_portb_sd_resources[2].start = (u32_t)&(sd_node->regs); + ip7145dpf_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); + + platform_device_register(&ip7145dpf_portb_sd_device); +} + + +#ifdef IP7145DPF_USE_MMC_SPI +/****************************************************************************** + * SPI over GPIO (MMC_SPI) + */ +#include +#include +#include +#include + +#define MMC_CS GPIO_RF_5 // PF5 D3 +#define MMC_CD GPIO_RA_4 // PA4 CD +#define MMC_WP IP7145DPF_IOB0 // IOB0 WP +#define MMC_PWR IP7145DPF_IOB4 // IOB4 PWR + +/* + * SPI bus over GPIO (for SD card) + */ +static struct ubicom32_spi_gpio_platform_data ip7145dpf_spi_gpio_data = { + .pin_mosi = GPIO_RF_0, // PF0 CMD + .pin_miso = GPIO_RF_2, // PF2 D0 + .pin_clk = GPIO_RF_1, // PF1 CLK + .bus_num = 0, // We'll call this SPI bus 0 + .num_chipselect = 1, // only one device on this SPI bus +}; + +static struct platform_device ip7145dpf_spi_gpio_device = { + .name = "ubicom32-spi-gpio", + .id = 0, + .dev = { + .platform_data = &ip7145dpf_spi_gpio_data, + }, +}; + +/* + * ip7145dpf_mmc_spi_setpower_slot_a + * Set the power state for slot A + */ +static void ip7145dpf_mmc_spi_setpower_slot_a(struct device *dev, unsigned int vdd) +{ + struct mmc_spi_platform_data *pd = dev->platform_data; + + /* + * Power is inverted, we could tell the IOB to do it, but it's cleaner this way. + */ + if ((1 << vdd) & pd->ocr_mask) { + gpio_set_value(MMC_PWR, 0); + return; + } + gpio_set_value(MMC_PWR, 1); +} + +/* + * ip7145dpf_mmc_spi_get_cd_slot_a + * Get the CD bit for slot A + */ +static int ip7145dpf_mmc_spi_get_cd_slot_a(struct device *dev) +{ + /* + * Note that the sense of the GPIO is inverted + */ + return !gpio_get_value(MMC_CD); +} + +/* + * ip7145dpf_mmc_spi_get_ro_slot_a + * Get the WP bit for slot A + */ +static int ip7145dpf_mmc_spi_get_ro_slot_a(struct device *dev) +{ + /* + * Note that the sense of the GPIO is inverted, we could tell the IOB to do it, but + * it's clearer this way. + */ + return !gpio_get_value(MMC_WP); +} + +/* + * ip7145dpf_mmc_spi_exit_slot_a + * Free the appropriate GPIOs for slot A SD slot. + */ +static void ip7145dpf_mmc_spi_exit_slot_a(struct device *dev, void *appdata) +{ + gpio_free(MMC_CD); + gpio_free(MMC_CS); + gpio_free(MMC_WP); + gpio_free(MMC_PWR); + platform_device_unregister(&ip7145dpf_spi_gpio_device); +} + +/* + * ip7145dpf_mmc_spi_init_slot_a + * Allocate the appropriate GPIOs for slot A SD slot. + * WP is on IOB0, CD is PA4, CS is on PF5 + * TODO: make CD an interrupt + */ +static int ip7145dpf_mmc_spi_init_slot_a(void) +{ + int ret = gpio_request(MMC_CD, "mmc-a-cd"); + if (ret) { + printk(KERN_ERR "%s: could not request mmc-a-cd pin\n", __FUNCTION__); + return -ENOSYS; + } + gpio_direction_input(MMC_CD); + + ret = gpio_request(MMC_CS, "mmc-a-cs"); + if (ret) { + printk(KERN_ERR "%s: could not request mmc-a-cs pin\n", __FUNCTION__); + goto no_cs; + } + gpio_direction_output(MMC_CS, 0); + + ret = gpio_request(MMC_WP, "mmc-a-wp"); + if (ret) { + printk(KERN_ERR "%s: could not request mmc-a-wp pin\n", __FUNCTION__); + goto no_wp; + } + gpio_direction_input(MMC_WP); + + /* + * Start off with power off + */ + ret = gpio_request(MMC_PWR, "mmc-a-pwr"); + if (ret) { + printk(KERN_ERR "%s: could not request mmc-a-pwr pin\n", __FUNCTION__); + goto no_pwr; + } + ret = gpio_direction_output(MMC_PWR, 1); + + return 0; + +no_pwr: + gpio_free(MMC_WP); + +no_wp: + gpio_free(MMC_CS); + +no_cs: + gpio_free(MMC_CD); + return -ENOSYS; +} + +/* + * MMC_SPI driver (currently bitbang) + */ +static struct mmc_spi_platform_data ip7145dpf_mmc_platform_data = { + .ocr_mask = MMC_VDD_33_34, + .exit = ip7145dpf_mmc_spi_exit_slot_a, + .get_ro = ip7145dpf_mmc_spi_get_ro_slot_a, + .get_cd = ip7145dpf_mmc_spi_get_cd_slot_a, + + .setpower = ip7145dpf_mmc_spi_setpower_slot_a, + .powerup_msecs = 500, + + .detect_delay = 100, + + .caps = MMC_CAP_NEEDS_POLL, +}; + +static struct ubicom32_spi_gpio_controller_data ip7145dpf_mmc_controller_data = { + .pin_cs = MMC_CS, +}; + +static struct spi_board_info ip7145dpf_spi_board_info[] = { + { + .modalias = "mmc_spi", + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 2000000, + .platform_data = &ip7145dpf_mmc_platform_data, + .controller_data = &ip7145dpf_mmc_controller_data, + } +}; +#endif /* IP7145DPF_USE_MMC_SPI */ + +/* + * ip7145dpf_u72_setup + * Called by I2C to tell us that u72 is setup. + * + * This function is called by I2C to tell us that u72 has been setup. All + * devices which rely on this chip being initialized (or even present) need to + * be initialized in this function otherwise they may get initialized too early. + * + * Currently the only device depending on u72 is the SPI + */ +static int __init ip7145dpf_u72_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *context) +{ +#ifdef IP7145DPF_USE_MMC_SPI + if (ip7145dpf_mmc_spi_init_slot_a()) { + printk(KERN_ERR "%s: could not request mmc resources\n", __FUNCTION__); + } else { + printk(KERN_INFO "%s: registering SPI resources\n", __FUNCTION__); + spi_register_board_info(ip7145dpf_spi_board_info, ARRAY_SIZE(ip7145dpf_spi_board_info)); + platform_device_register(&ip7145dpf_spi_gpio_device); + } +#else + /* + * Initialize the Port F/Port B SD slots + */ + ip7145dpf_portf_sd_init(); + ip7145dpf_portb_sd_init(); +#endif + return 0; +} + +/****************************************************************************** + * LCD VGH on the board at PE6 + */ +static struct ubicom32lcdpower_platform_data ip7145dpf_lcdpower_data = { + .vgh_gpio = GPIO_RE_6, + .vgh_polarity = true, +}; + +static struct platform_device ip7145dpf_lcdpower_device = { + .name = "ubicom32lcdpower", + .id = -1, + .dev = { + .platform_data = &ip7145dpf_lcdpower_data, + }, +}; + +/****************************************************************************** + * Backlight on the board PD0, hardware PWM + */ +static struct ubicom32bl_platform_data ip7145dpf_backlight_data = { + .type = UBICOM32BL_TYPE_PWM, + .pwm_channel = 2, + .pwm_prescale = 15, + .pwm_period = 60, + .default_intensity = 0x80, +}; + +static struct platform_device ip7145dpf_backlight_device = { + .name = "ubicom32bl", + .id = -1, + .dev = { + .platform_data = &ip7145dpf_backlight_data, + }, +}; + +/****************************************************************************** + * Ubicom32Input on I2C, U48 MAX7310, address 0x18, 8 bits + */ +static struct ubicom32input_i2c_button ip7145dpf_ubicom32input_i2c_u48_buttons[] = { + { + .type = EV_KEY, + .code = KEY_UP, + .bit = 0, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_LEFT, + .bit = 1, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_RIGHT, + .bit = 2, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_DOWN, + .bit = 3, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_ENTER, + .bit = 4, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_MENU, + .bit = 5, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_ESC, + .bit = 6, + .active_low = 1, + }, +}; + +static struct ubicom32input_i2c_platform_data ip7145dpf_ubicom32input_i2c_u48_platform_data = { + .buttons = ip7145dpf_ubicom32input_i2c_u48_buttons, + .nbuttons = ARRAY_SIZE(ip7145dpf_ubicom32input_i2c_u48_buttons), + .name = "Ubicom32 Input I2C U48", +}; + +/****************************************************************************** + * Additional GPIO chips + */ +static struct pca953x_platform_data ip7145dpf_gpio_u72_platform_data = { + .gpio_base = IP7145DPF_U72_BASE, + .setup = ip7145dpf_u72_setup, +}; + +/****************************************************************************** + * Devices on the I2C bus + */ +static struct i2c_board_info __initdata ip7145dpf_i2c_board_info[] = { + /* + * U51, S35390A RTC, address 0x30 + */ + { + .type = "s35390a", + .addr = 0x30, + }, + + /* + * U48, MAX7310 IO expander, 8 bits, address 0x18 + */ + { + .type = "ubicom32in_max7310", + .addr = 0x18, + .platform_data = &ip7145dpf_ubicom32input_i2c_u48_platform_data, + }, + + /* + * U72, MAX7310 IOB expander, 8 bits, address 0x19 + */ + { + .type = "max7310", + .addr = 0x19, + .platform_data = &ip7145dpf_gpio_u72_platform_data, + }, +}; + +/* + * I2C bus on the board, SDA PE1, SCL PE2 + */ +static struct i2c_gpio_platform_data ip7145dpf_i2c_data = { + .sda_pin = GPIO_RE_1, + .scl_pin = GPIO_RE_2, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, +}; + +static struct platform_device ip7145dpf_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ip7145dpf_i2c_data, + }, +}; + +/****************************************************************************** + * Use ubicom32input driver to monitor the various pushbuttons on this board. + * + * WPS PF12 + * FACT_DEFAULT PF13 + * POWER PE4 + * + * Not sutable for the keypad buttons since those run on I2C GPIO. The polling + * of ubicom32input would seem to be excessive for this. + * + * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default + */ +static struct ubicom32input_button ip7145dpf_ubicom32input_buttons[] = { + { + .type = EV_KEY, + .code = KEY_FN_F1, + .gpio = GPIO_RF_12, + .desc = "WPS", + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_FN_F2, + .gpio = GPIO_RF_13, + .desc = "Factory Default", + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_POWER, + .gpio = GPIO_RE_4, + .desc = "Power", + .active_low = 1, + }, +}; + +static struct ubicom32input_platform_data ip7145dpf_ubicom32input_data = { + .buttons = ip7145dpf_ubicom32input_buttons, + .nbuttons = ARRAY_SIZE(ip7145dpf_ubicom32input_buttons), +}; + +static struct platform_device ip7145dpf_ubicom32input_device = { + .name = "ubicom32input", + .id = -1, + .dev = { + .platform_data = &ip7145dpf_ubicom32input_data, + }, +}; + +/* + * List of all devices in our system + */ +static struct platform_device *ip7145dpf_devices[] __initdata = { + &ip7145dpf_i2c_device, + &ip7145dpf_lcdpower_device, + &ip7145dpf_backlight_device, + &ip7145dpf_ubicom32input_device, +}; + +/* + * ip7145dpf_power_off + * Called to turn the power off for this board + */ +static void ip7145dpf_power_off(void) +{ + gpio_set_value(GPIO_RE_5, 0); +} + +/* + * ip7145dpf_init + * Called to add the devices which we have on this board + */ +static int __init ip7145dpf_init(void) +{ + int ret; + struct platform_device *audio_dev; + + ubi_gpio_init(); + +#ifdef CONFIG_UIO_UBICOM32RING + ring_tio_init("decoder_ring"); +#endif + + /* + * Start up the video driver first + */ + vdc_tio_init(); + + /* + * Take over holding of the power from the system + */ + ret = gpio_request(GPIO_RE_5, "power_hold"); + if (ret) { + printk(KERN_ERR "%s: could not request power hold GPIO\n", __FUNCTION__); + } + gpio_direction_output(GPIO_RE_5, 1); + mach_power_off = ip7145dpf_power_off; + + /* + * USB SEL_HOST_USB line + */ + ret = gpio_request(GPIO_RF_11, "SEL_HOST_USB"); + if (ret) { + printk(KERN_ERR "%s: could not request SEL_HOST_USB GPIO\n", __FUNCTION__); + } + gpio_direction_output(GPIO_RF_11, 0); + + /* + * Setup audio + */ + audio_dev = audio_device_alloc("snd-ubi32-generic", "audio", "audio-i2sout", 0); + if (audio_dev) { + platform_device_register(audio_dev); + } + + /* + * Register all of the devices we have on this board + */ + printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); + platform_add_devices(ip7145dpf_devices, ARRAY_SIZE(ip7145dpf_devices)); + + /* + * Register all of the devices which sit on the I2C bus + */ + printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); + i2c_register_board_info(0, ip7145dpf_i2c_board_info, ARRAY_SIZE(ip7145dpf_i2c_board_info)); + + /* + * We have to initialize the SPI after the I2C IOB gets setup. SPI is initialized in + * ip7145dpf_u72_setup + */ + + return 0; +} + +arch_initcall(ip7145dpf_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160bringup.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160bringup.c new file mode 100644 index 000000000..2527d8d7d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160bringup.c @@ -0,0 +1,134 @@ +/* + * arch/ubicom32/mach-ip7k/board-ip7160bringup.c + * Support for the IP7160 bringup board. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_SERIAL_UBI32_SERDES +#include +#endif + +/* + * Use ubicom32input driver to monitor the various pushbuttons on this board. + * + * WPS PD5 + * FACT_DEFAULT PD6 + * + * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default + */ +static struct ubicom32input_button ip7160bringup_ubicom32input_buttons[] = { + { + .type = EV_KEY, + .code = KEY_FN_F1, + .gpio = GPIO_RD_5, + .desc = "WPS", + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_FN_F2, + .gpio = GPIO_RD_6, + .desc = "Factory Default", + .active_low = 1, + }, +}; + +static struct ubicom32input_platform_data ip7160bringup_ubicom32input_data = { + .buttons = ip7160bringup_ubicom32input_buttons, + .nbuttons = ARRAY_SIZE(ip7160bringup_ubicom32input_buttons), +}; + +static struct platform_device ip7160bringup_ubicom32input_device = { + .name = "ubicom32input", + .id = -1, + .dev = { + .platform_data = &ip7160bringup_ubicom32input_data, + }, +}; + +#ifdef CONFIG_SERIAL_UBI32_SERDES +static struct resource ip7160bringup_ubicom32_suart_resources[] = { + { + .start = RE, + .end = RE, + .flags = IORESOURCE_MEM, + }, + { + .start = PORT_OTHER_INT(RE), + .end = PORT_OTHER_INT(RE), + .flags = IORESOURCE_IRQ, + }, + { + .start = 250000000, + .end = 250000000, + .flags = UBICOM32_SUART_IORESOURCE_CLOCK, + }, +}; + +static struct platform_device ip7160bringup_ubicom32_suart_device = { + .name = "ubicom32suart", + .id = -1, + .num_resources = ARRAY_SIZE(ip7160bringup_ubicom32_suart_resources), + .resource = ip7160bringup_ubicom32_suart_resources, +}; +#endif + +/* + * List of all devices in our system + */ +static struct platform_device *ip7160bringup_devices[] __initdata = { +#ifdef CONFIG_SERIAL_UBI32_SERDES + &ip7160bringup_ubicom32_suart_device, +#endif + &ip7160bringup_ubicom32input_device, +}; + +/* + * ip7160bringup_init + * Called to add the devices which we have on this board + */ +static int __init ip7160bringup_init(void) +{ + board_init(); + + ubi_gpio_init(); + + printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); + platform_add_devices(ip7160bringup_devices, ARRAY_SIZE(ip7160bringup_devices)); + + return 0; +} + +arch_initcall(ip7160bringup_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160dpf.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160dpf.c new file mode 100644 index 000000000..7f4e4f3e4 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160dpf.c @@ -0,0 +1,326 @@ +/* + * arch/ubicom32/mach-ip7k/board-ip7160dpf.c + * Platform initialization for ip7160dpf board. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* + * Backlight on the board PD0, hardware PWM + */ +static const struct ubicom32hid_button ip7160dpf_ubicom32hid_buttons[] = { + { + .type = EV_KEY, + .code = KEY_UP, + .bit = 0, + }, + { + .type = EV_KEY, + .code = KEY_LEFT, + .bit = 1, + }, + { + .type = EV_KEY, + .code = KEY_RIGHT, + .bit = 2, + }, + { + .type = EV_KEY, + .code = KEY_DOWN, + .bit = 3, + }, + { + .type = EV_KEY, + .code = KEY_ENTER, + .bit = 4, + }, + { + .type = EV_KEY, + .code = KEY_MENU, + .bit = 5, + }, + { + .type = EV_KEY, + .code = KEY_ESC, + .bit = 7, + }, +}; + +static const struct ubicom32hid_ir ip7160dpf_ubicom32hid_ircodes[] = { + { + .type = EV_KEY, + .code = KEY_UP, + .ir_code = 0xF807916E + }, + { + .type = EV_KEY, + .code = KEY_DOWN, + .ir_code = 0xF20D916E + }, + { + .type = EV_KEY, + .code = KEY_LEFT, + .ir_code = 0xF609916E + }, + { + .type = EV_KEY, + .code = KEY_RIGHT, + .ir_code = 0xF40B916E + }, + { + .type = EV_KEY, + .code = KEY_ENTER, + .ir_code = 0xF50A916E + }, + { /* rotate */ + .type = EV_KEY, + .code = KEY_FN_F1, + .ir_code = 0xF906916E + }, + { + .type = EV_KEY, + .code = KEY_MENU, + .ir_code = 0xF708916E + }, + { /* font size */ + .type = EV_KEY, + .code = KEY_FN_F2, + .ir_code = 0xF30C916E + }, + { + .type = EV_KEY, + .code = KEY_ESC, + .ir_code = 0xF10E916E + }, + { + .type = EV_KEY, + .code = KEY_VOLUMEUP, + .ir_code = 0xF00F916E + }, + { + .type = EV_KEY, + .code = KEY_VOLUMEDOWN, + .ir_code = 0xED12916E + }, + { + .type = EV_KEY, + .code = KEY_MUTE, + .ir_code = 0xEA15916E + }, + { + .type = EV_KEY, + .code = KEY_INFO, + .ir_code = 0xEF10916E + }, + { /* Like */ + .type = EV_KEY, + .code = KEY_FN_F3, + .ir_code = 0xEE11916E + }, + { /* Dislike */ + .type = EV_KEY, + .code = KEY_FN_F4, + .ir_code = 0xEB14916E + }, + { + .type = EV_KEY, + .code = KEY_POWER, + .ir_code = 0xFD02916E + }, +}; + +static struct ubicom32hid_platform_data ip7160dpf_ubicom32hid_platform_data = { + .gpio_reset = GPIO_RI_5, + .gpio_reset_polarity = 0, + .type = UBICOM32HID_BL_TYPE_PWM, + .invert = 0, + .default_intensity = 128, + .buttons = ip7160dpf_ubicom32hid_buttons, + .nbuttons = ARRAY_SIZE(ip7160dpf_ubicom32hid_buttons), + .ircodes = ip7160dpf_ubicom32hid_ircodes, + .nircodes = ARRAY_SIZE(ip7160dpf_ubicom32hid_ircodes), +}; + +/* + * Devices on the I2C bus + * This board has a "bus 2" which is isolated from the main bus by U47 + * and pin RI0. It should be safe to always enable bus 2 by setting + * RI0 to low, however, it should be noted that on all existing configurations + * of this board, U49 and U51 are not populated. + */ +static struct i2c_board_info __initdata ip7160dpf_i2c_board_info[] = { + /* + * U37, CS4350 DAC, address 0x4B, bus 2 + * THIS ENTRY MUST BE FIRST + */ + { + .type = "cs4350", + .addr = 0x4B, + } + + /* + * U24, ubicom32hid + */ + { + .type = "ubicom32hid", + .addr = 0x08, + .platform_data = &ip7160dpf_ubicom32hid_platform_data, + }, + + /* + * U49, ISL29001 Ambient Light Sensor, address 0x44, bus 2 (may not be stuffed) + */ + + /* + * U51, S35390A RTC, address 0x30, bus 2 (may not be stuffed) + */ +#ifdef CONFIG_RTC_DRV_S35390A + { + .type = "s35390a", + .addr = 0x30, + }, +#endif +}; + +/* + * I2C bus on the board, SDA PI1, SCL PI2 + */ +static struct i2c_gpio_platform_data ip7160dpf_i2c_data = { + .sda_pin = GPIO_RI_1, + .scl_pin = GPIO_RI_2, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 1, + .udelay = 6, +}; + +static struct platform_device ip7160dpf_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ip7160dpf_i2c_data, + }, +}; + +/* + * List of all devices in our system + */ +static struct platform_device *ip7160dpf_devices[] __initdata = { + &ip7160dpf_i2c_device, +}; + +/* + * ip7160dpf_power_off + * Called to turn the power off for this board + */ +static void ip7160dpf_power_off(void) +{ + gpio_set_value(GPIO_RF_14, 0); +} + +/* + * ip7160dpf_init + * Called to add the devices which we have on this board + */ +static int __init ip7160dpf_init(void) +{ + int ret; + struct platform_device *audio_dev; + + ubi_gpio_init(); + + /* + * Hold the POWER_HOLD line + */ + ret = gpio_request(GPIO_RF_14, "POWER_HOLD"); + if (ret) { + printk(KERN_ERR "%s: could not request POWER_HOLD GPIO\n", __FUNCTION__); + } + gpio_direction_output(GPIO_RF_14, 1); + mach_power_off = ip7160dpf_power_off; + + /* + * USB SEL_HOST_USB line + */ + ret = gpio_request(GPIO_RI_13, "SEL_HOST_USB"); + if (ret) { + printk(KERN_ERR "%s: could not request SEL_HOST_USB GPIO\n", __FUNCTION__); + } + gpio_direction_output(GPIO_RI_13, 0); + + /* + * USB/DAC nRESET line + */ + ret = gpio_request(GPIO_RI_3, "USB_DAC_nRESET"); + if (ret) { + printk(KERN_ERR "%s: could not request USB_DAC_nRESET GPIO\n", __FUNCTION__); + } + gpio_direction_output(GPIO_RI_3, 0); + udelay(1); + gpio_direction_output(GPIO_RI_3, 1); + + /* + * I2C BUS2 Disable line + */ + ret = gpio_request(GPIO_RI_0, "DISABLE_BUS2"); + if (ret) { + printk(KERN_ERR "%s: could not request DISABLE_BUS2 GPIO\n", __FUNCTION__); + } + gpio_direction_output(GPIO_RI_0, 0); + + vdc_tio_init(); + + printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); + platform_add_devices(ip7160dpf_devices, ARRAY_SIZE(ip7160dpf_devices)); + + /* + * Allocate the audio driver if we can + */ + audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio-i2sout", 0); + if (audio_dev) { + ip7160dpf_i2c_board_info[0].platform_data = audio_dev; + } + + printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); + i2c_register_board_info(0, ip7160dpf_i2c_board_info, ARRAY_SIZE(ip7160dpf_i2c_board_info)); + + return 0; +} + +arch_initcall(ip7160dpf_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160rgw.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160rgw.c new file mode 100644 index 000000000..4d50375a7 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160rgw.c @@ -0,0 +1,355 @@ +/* + * arch/ubicom32/mach-ip7k/board-ip7160rgw.c + * Platform initialization for ip7160rgw board. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_SERIAL_UBI32_SERDES +#include +#endif + +#include +#include + +#ifdef CONFIG_IP7160RGWLCD +#include +#include +/* + * LCD Adapter board 8007-092x support + * + * Touch controller + * + * Connected via I2C bus, interrupt on PA6 + */ +#include + +/* + * ip7160rgwlcd_tsc2007_exit_platform_hw + */ +static void ip7160rgwlcd_tsc2007_exit_platform_hw(void) +{ + UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 17); + gpio_free(GPIO_RA_5); +} + +/* + * ip7160rgwlcd_tsc2007_init_platform_hw + */ +static int ip7160rgwlcd_tsc2007_init_platform_hw(void) +{ + int res = gpio_request(GPIO_RA_5, "TSC2007_IRQ"); + if (res) { + return res; + } + + UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 17); + UBICOM32_IO_PORT(RA)->ctl0 |= (0x02 << 17); + return 0; +} + +/* + * ip7160rgwlcd_tsc2007_get_pendown_state + */ +static int ip7160rgwlcd_tsc2007_get_pendown_state(void) +{ + return !gpio_get_value(GPIO_RA_5); +} + +static struct tsc2007_platform_data ip7160rgwlcd_tsc2007_data = { + .model = 2007, + .x_plate_ohms = 350, + .get_pendown_state = ip7160rgwlcd_tsc2007_get_pendown_state, + .init_platform_hw = ip7160rgwlcd_tsc2007_init_platform_hw, + .exit_platform_hw = ip7160rgwlcd_tsc2007_exit_platform_hw, +}; + +/****************************************************************************** + * I2C bus on the board, SDA PI14, SCL PI13 + */ +static struct i2c_gpio_platform_data ip7160rgwlcd_i2c_data = { + .sda_pin = GPIO_RI_14, + .scl_pin = GPIO_RI_13, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .udelay = 50, +}; + +static struct platform_device ip7160rgwlcd_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ip7160rgwlcd_i2c_data, + }, +}; + +static struct i2c_board_info __initdata ip7160rgwlcd_i2c_board_info[] = { + { + .type = "tsc2007", + .addr = 0x48, + .irq = 45, // RA5 + .platform_data = &ip7160rgwlcd_tsc2007_data, + }, +}; + +#endif + +/* + * SPI bus over GPIO for Gigabit Ethernet Switch + * U58: + * MOSI PE0 + * MISO PE1 + * CLK PE3 + * CS PE2 + */ +static struct ubicom32_spi_gpio_platform_data ip7160rgw_spi_gpio_data = { + .pin_mosi = GPIO_RE_0, + .pin_miso = GPIO_RE_1, + .pin_clk = GPIO_RE_3, + .bus_num = 0, // We'll call this SPI bus 0 + .num_chipselect = 1, // only one device on this SPI bus + .clk_default = 1, +}; + +static struct platform_device ip7160rgw_spi_gpio_device = { + .name = "ubicom32-spi-gpio", + .id = 0, + .dev = { + .platform_data = &ip7160rgw_spi_gpio_data, + }, +}; + +static struct ubicom32_spi_gpio_controller_data ip7160rgw_bcm539x_controller_data = { + .pin_cs = GPIO_RE_2, +}; + +static struct switch_core_platform_data ip7160rgw_bcm539x_platform_data = { + .flags = SWITCH_DEV_FLAG_HW_RESET, + .pin_reset = GPIO_RE_4, + .name = "bcm539x", +}; + +static struct spi_board_info ip7160rgw_spi_board_info[] = { + { + .modalias = "bcm539x-spi", + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 2000000, + .platform_data = &ip7160rgw_bcm539x_platform_data, + .controller_data = &ip7160rgw_bcm539x_controller_data, + .mode = SPI_MODE_3, + } +}; + +/* + * LEDs + * + * WLAN1 PD0 (PWM capable) + * WLAN2 PD1 + * USB2.0 PD2 + * Status PD3 + * WPS PD4 + * + * TODO: check triggers, are they generic? + */ +static struct gpio_led ip7160rgw_gpio_leds[] = { + { + .name = "d53:green:WLAN1", + .default_trigger = "WLAN1", + .gpio = GPIO_RD_0, + .active_low = 1, + }, + { + .name = "d54:green:WLAN2", + .default_trigger = "WLAN2", + .gpio = GPIO_RD_1, + .active_low = 1, + }, + { + .name = "d55:green:USB", + .default_trigger = "USB", + .gpio = GPIO_RD_2, + .active_low = 1, + }, + { + .name = "d56:green:Status", + .default_trigger = "Status", + .gpio = GPIO_RD_3, + .active_low = 1, + }, + { + .name = "d57:green:WPS", + .default_trigger = "WPS", + .gpio = GPIO_RD_4, + .active_low = 1, + }, +}; + +static struct gpio_led_platform_data ip7160rgw_gpio_led_platform_data = { + .num_leds = 5, + .leds = ip7160rgw_gpio_leds, +}; + +static struct platform_device ip7160rgw_gpio_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &ip7160rgw_gpio_led_platform_data, + }, +}; + +/* + * Use ubicom32input driver to monitor the various pushbuttons on this board. + * + * WPS PD5 + * FACT_DEFAULT PD6 + * + * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default + */ +static struct ubicom32input_button ip7160rgw_ubicom32input_buttons[] = { + { + .type = EV_KEY, + .code = KEY_FN_F1, + .gpio = GPIO_RD_5, + .desc = "WPS", + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_FN_F2, + .gpio = GPIO_RD_6, + .desc = "Factory Default", + .active_low = 1, + }, +}; + +static struct ubicom32input_platform_data ip7160rgw_ubicom32input_data = { + .buttons = ip7160rgw_ubicom32input_buttons, + .nbuttons = ARRAY_SIZE(ip7160rgw_ubicom32input_buttons), +}; + +static struct platform_device ip7160rgw_ubicom32input_device = { + .name = "ubicom32input", + .id = -1, + .dev = { + .platform_data = &ip7160rgw_ubicom32input_data, + }, +}; + +#ifdef CONFIG_SERIAL_UBI32_SERDES +static struct resource ip7160rgw_ubicom32_suart_resources[] = { + { + .start = RE, + .end = RE, + .flags = IORESOURCE_MEM, + }, + { + .start = PORT_OTHER_INT(RE), + .end = PORT_OTHER_INT(RE), + .flags = IORESOURCE_IRQ, + }, + { + .start = 250000000, + .end = 250000000, + .flags = UBICOM32_SUART_IORESOURCE_CLOCK, + }, +}; + +static struct platform_device ip7160rgw_ubicom32_suart_device = { + .name = "ubicom32suart", + .id = -1, + .num_resources = ARRAY_SIZE(ip7160rgw_ubicom32_suart_resources), + .resource = ip7160rgw_ubicom32_suart_resources, +}; +#endif + +/* + * List of all devices in our system + */ +static struct platform_device *ip7160rgw_devices[] __initdata = { +#ifdef CONFIG_SERIAL_UBI32_SERDES + &ip7160rgw_ubicom32_suart_device, +#endif + &ip7160rgw_ubicom32input_device, + &ip7160rgw_gpio_leds_device, + &ip7160rgw_spi_gpio_device, +#ifdef CONFIG_IP7160RGWLCD + &ip7160rgwlcd_i2c_device, +#endif +}; + +/* + * ip7160rgw_init + * Called to add the devices which we have on this board + */ +static int __init ip7160rgw_init(void) +{ + board_init(); + + /* + * Rev 1.2 boards have spi in a different place than 1.1/1.0 + */ + if (strcmp(board_get_revision(), "1.2") == 0) { + ip7160rgw_spi_gpio_data.pin_mosi = GPIO_RD_7; + } + + ubi_gpio_init(); + + /* + * Reserve switch SPI CS on behalf on switch driver + */ + if (gpio_request(ip7160rgw_bcm539x_controller_data.pin_cs, "switch-bcm539x-cs")) { + printk(KERN_WARNING "Could not request cs of switch SPI I/F\n"); + return -EIO; + } + gpio_direction_output(ip7160rgw_bcm539x_controller_data.pin_cs, 1); + + printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); + platform_add_devices(ip7160rgw_devices, ARRAY_SIZE(ip7160rgw_devices)); + + printk(KERN_INFO "%s: registering SPI resources\n", __FUNCTION__); + spi_register_board_info(ip7160rgw_spi_board_info, ARRAY_SIZE(ip7160rgw_spi_board_info)); + +#ifdef CONFIG_IP7160RGWLCD + printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); + i2c_register_board_info(0, ip7160rgwlcd_i2c_board_info, ARRAY_SIZE(ip7160rgwlcd_i2c_board_info)); + printk(KERN_INFO "IP7160 RGW + LCD\n"); +#else + printk(KERN_INFO "IP7160 RGW\n"); +#endif + return 0; +} + +arch_initcall(ip7160rgw_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500av.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500av.c new file mode 100644 index 000000000..7cd25fcd3 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500av.c @@ -0,0 +1,273 @@ +/* + * arch/ubicom32/mach-ip7k/board-ip7500av.c + * Support for IP7500 Audio Video Board + CPU module board. + * + * This file supports the IP7500 Audio Video Board: + * 8007-0810 Rev 1.0 + * with one of the following CPU module boards: + * 8007-0510 Rev 1.0 + * 8007-0510A Rev 1.0 (with ethernet) + * + * DIP Switch SW2 configuration: (*) default + * POS 1: on(*) = PCI enabled, off = PCI disabled + * POS 2: on(*) = TTYX => PA6, off = TTYX => PF12 + * POS 3: on(*) = TTYY => PA7, off = TTYY => PF15 + * POS 4: unused + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Devices on the I2C bus + * + * BEWARE of changing the order of things in this array as we depend on + * certain things to be in certain places. + */ +static struct i2c_board_info __initdata ip7500av_i2c_board_info[] = { + /* + * U6, CS4384 DAC, address 0x19 + */ + { + .type = "cs4384", + .addr = 0x19, + }, +}; + +/* + * I2C bus on the board, SDA PD1, SCL PD2 + */ +static struct i2c_gpio_platform_data ip7500av_i2c_data = { + .sda_pin = GPIO_RD_6, + .scl_pin = GPIO_RD_3, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .udelay = 50, +}; + +static struct platform_device ip7500av_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ip7500av_i2c_data, + }, +}; + +/* + * List of possible mclks we can generate. This depends on the CPU frequency. + */ +static struct ubi32_cs4384_mclk_entry ip7500av_cs4384_mclk_entries[] = { + { + .rate = 12288000, + .div = 44, + }, + { + .rate = 11289600, + .div = 48, + }, +}; + +/* + * List of all devices in our system + */ +static struct platform_device *ip7500av_devices[] __initdata = { + &ip7500av_i2c_device, +}; + +/* + * ip7500av_vdac_write + */ +static int __init ip7500av_vdac_write(int reg, int val) +{ + struct i2c_adapter *adap; + struct i2c_msg msg[1]; + unsigned char data[2]; + int err; + + adap = i2c_get_adapter(0); + if (!adap) { + printk(KERN_WARNING "%s: failed to get i2c adapter\n", __FUNCTION__); + return -ENODEV; + } + msg->addr = 0x2B; + msg->flags = 0; + msg->len = 2; + msg->buf = data; + data[0] = reg; + data[1] = val; + err = i2c_transfer(adap, msg, 1); + i2c_put_adapter(adap); + if (err >= 0) { + return 0; + } + return err; +} + +/* + * ip7500av_vdac_init + * Initializes the video DAC via I2C + * + * Equivalent mode line: 720x480p = 27 Mhz, 720 736 800 858 480 484 492 525 + */ +static int __init ip7500av_vdac_init(void) +{ + int err; + + printk(KERN_INFO "Initializing ADV7393 DAC\n"); + + /* + * Reset the VDAC + */ + if (gpio_request(GPIO_RF_6, "VDAC Reset")) { + printk(KERN_WARNING "%s: failed to allocate VDAC Reset\n", __FUNCTION__); + return -EBUSY; + } + gpio_direction_output(GPIO_RF_6, 0); + udelay(1); + gpio_set_value(GPIO_RF_6, 1); + + /* + * See table 100 of ADV7393 data sheet: 16-bit 525p YCrCb In, YPbPr Out + */ + err = ip7500av_vdac_write(0x17, 0x02); + if (err) { + printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); + return err; + } + err = ip7500av_vdac_write(0x00, 0x1c); + if (err) { + printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); + return err; + } + err = ip7500av_vdac_write(0x01, 0x10); + if (err) { + printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); + return err; + } + err = ip7500av_vdac_write(0x31, 0x01); + if (err) { + printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); + return err; + } +#ifdef IP7500AV_VDAC_SWAP_PBPR + err = ip7500av_vdac_write(0x35, 0x08); + if (err) { + printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); + return err; + } +#endif +#ifdef IP7500AV_VDAC_FULL_RANGE + err = ip7500av_vdac_write(0x30, 0x02); + if (err) { + printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); + return err; + } +#endif + return 0; +} +late_initcall(ip7500av_vdac_init); + +/* + * ip7500av_init + * Called to add the devices which we have on this board + */ +static int __init ip7500av_init(void) +{ + struct platform_device *audio_dev; + struct platform_device *audio_dev2; + struct ubi32_cs4384_platform_data *cs4384_pd; + + board_init(); + + ubi_gpio_init(); + + vdc_tio_init(); + + printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); + platform_add_devices(ip7500av_devices, ARRAY_SIZE(ip7500av_devices)); + + /* + * CS4384 DAC + */ + audio_dev = audio_device_alloc("snd-ubi32-cs4384", "audio", "audio-i2sout", + sizeof(struct ubi32_cs4384_platform_data)); + if (audio_dev) { + /* + * Attempt to figure out a good divisor. This will only work + * assuming the core frequency is compatible. + */ + int i; + unsigned int freq = processor_frequency(); + for (i = 0; i < ARRAY_SIZE(ip7500av_cs4384_mclk_entries); i++) { + unsigned int div; + unsigned int rate = ip7500av_cs4384_mclk_entries[i].rate / 1000; + div = ((freq / rate) + 500) / 1000; + ip7500av_cs4384_mclk_entries[i].div = div; + printk("CS4384 mclk %d rate %u000Hz div %u act %u\n", i, rate, div, freq / div); + } + + cs4384_pd = audio_device_priv(audio_dev); + cs4384_pd->mclk_src = UBI32_CS4384_MCLK_PWM_0; + cs4384_pd->n_mclk = ARRAY_SIZE(ip7500av_cs4384_mclk_entries); + cs4384_pd->mclk_entries = ip7500av_cs4384_mclk_entries; + ip7500av_i2c_board_info[0].platform_data = audio_dev; + + /* + * Reset the DAC + */ + if (gpio_request(GPIO_RF_4, "DAC Reset") == 0) { + gpio_direction_output(GPIO_RF_4, 0); + udelay(1); + gpio_direction_output(GPIO_RF_4, 1); + } else { + printk("Unable to request DAC reset GPIO\n"); + } + } + + /* + * SPDIF port + */ + audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0); + if (audio_dev2) { + platform_device_register(audio_dev2); + } + + /* + * Register all of the devices which sit on the I2C bus + */ + printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); + i2c_register_board_info(0, ip7500av_i2c_board_info, ARRAY_SIZE(ip7500av_i2c_board_info)); + + printk(KERN_INFO "IP7500 Audio/Video Board\n"); + return 0; +} +arch_initcall(ip7500av_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500iap.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500iap.c new file mode 100644 index 000000000..f565cdda1 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500iap.c @@ -0,0 +1,414 @@ +/* + * arch/ubicom32/mach-ip7k/board-ip7500iap.c + * Support for IP7500 Internet Audio Player + * + * This file supports the IP7500 Internet Audio Player: + * 8007-1110 Rev 1.0 + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +/****************************************************************************** + * SD/IO Port F (Slot 1) platform data + */ +static struct resource ip7500iap_portf_sd_resources[] = { + /* + * Send IRQ + */ + [0] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Receive IRQ + */ + [1] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Memory Mapped Registers + */ + [2] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct ubicom32sd_card ip7500iap_portf_sd_cards[] = { + [0] = { + .pin_wp = GPIO_RF_7, + .wp_polarity = 1, + .pin_pwr = GPIO_RF_8, + .pin_cd = GPIO_RF_6, + }, +}; + +static struct ubicom32sd_platform_data ip7500iap_portf_sd_platform_data = { + .ncards = 1, + .cards = ip7500iap_portf_sd_cards, +}; + +static struct platform_device ip7500iap_portf_sd_device = { + .name = "ubicom32sd", + .id = 0, + .resource = ip7500iap_portf_sd_resources, + .num_resources = ARRAY_SIZE(ip7500iap_portf_sd_resources), + .dev = { + .platform_data = &ip7500iap_portf_sd_platform_data, + }, + +}; + +/* + * ip7500iap_portf_sd_init + */ +static void ip7500iap_portf_sd_init(void) +{ + /* + * Check the device tree for the sd_tio + */ + struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd"); + if (!sd_node) { + printk(KERN_INFO "PortF SDTIO not found\n"); + return; + } + + /* + * Fill in the resources and platform data from devtree information + */ + ip7500iap_portf_sd_resources[0].start = sd_node->dn.sendirq; + ip7500iap_portf_sd_resources[1].start = sd_node->dn.recvirq; + ip7500iap_portf_sd_resources[2].start = (u32_t)&(sd_node->regs); + ip7500iap_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); + + platform_device_register(&ip7500iap_portf_sd_device); +} + +/****************************************************************************** + * SD/IO Port B (Slot 2) platform data + */ +static struct resource ip7500iap_portb_sd_resources[] = { + /* + * Send IRQ + */ + [0] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Receive IRQ + */ + [1] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Memory Mapped Registers + */ + [2] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct ubicom32sd_card ip7500iap_portb_sd_cards[] = { + [0] = { + .pin_wp = GPIO_RB_13, + .wp_polarity = 1, + .pin_pwr = GPIO_RB_11, + .pin_cd = GPIO_RB_12, + }, +}; + +static struct ubicom32sd_platform_data ip7500iap_portb_sd_platform_data = { + .ncards = 1, + .cards = ip7500iap_portb_sd_cards, +}; + +static struct platform_device ip7500iap_portb_sd_device = { + .name = "ubicom32sd", + .id = 1, + .resource = ip7500iap_portb_sd_resources, + .num_resources = ARRAY_SIZE(ip7500iap_portb_sd_resources), + .dev = { + .platform_data = &ip7500iap_portb_sd_platform_data, + }, + +}; + +/* + * ip7500iap_portb_sd_init + */ +static void ip7500iap_portb_sd_init(void) +{ + /* + * Check the device tree for the sd_tio + */ + struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd"); + if (!sd_node) { + printk(KERN_INFO "PortB SDTIO not found\n"); + return; + } + + /* + * Fill in the resources and platform data from devtree information + */ + ip7500iap_portb_sd_resources[0].start = sd_node->dn.sendirq; + ip7500iap_portb_sd_resources[1].start = sd_node->dn.recvirq; + ip7500iap_portb_sd_resources[2].start = (u32_t)&(sd_node->regs); + ip7500iap_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); + + platform_device_register(&ip7500iap_portb_sd_device); +} + +/****************************************************************************** + * Touch controller + * + * Connected via I2C bus, interrupt on PA6 + */ +#include + +/* + * ip7500iap_tsc2007_exit_platform_hw + */ +static void ip7500iap_tsc2007_exit_platform_hw(void) +{ + UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 19); + gpio_free(GPIO_RA_6); +} + +/* + * ip7500iap_tsc2007_init_platform_hw + */ +static int ip7500iap_tsc2007_init_platform_hw(void) +{ + int res = gpio_request(GPIO_RA_6, "TSC2007_IRQ"); + if (res) { + return res; + } + + UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 19); + UBICOM32_IO_PORT(RA)->ctl0 |= (0x02 << 19); + return 0; +} + +/* + * ip7500iap_tsc2007_get_pendown_state + */ +static int ip7500iap_tsc2007_get_pendown_state(void) +{ + return !gpio_get_value(GPIO_RA_6); +} + +static struct tsc2007_platform_data ip7500iap_tsc2007_data = { + .model = 2007, + .x_plate_ohms = 350, + .get_pendown_state = ip7500iap_tsc2007_get_pendown_state, + .init_platform_hw = ip7500iap_tsc2007_init_platform_hw, + .exit_platform_hw = ip7500iap_tsc2007_exit_platform_hw, +}; + +/****************************************************************************** + * i2c devices + * + * DO NOT CHANGE THE ORDER HERE unless you know how this works. There + * are hardcoded indicies which refer to the order of drivers listed here. + */ +static struct i2c_board_info __initdata ip7500iap_i2c_board_info[] = { + /* + * U6, CS4350 DAC, address 0x4B + */ + { + .type = "cs4350", + .addr = 0x4B, + }, + + /* + * U20, S35390A RTC, address 0x30 + */ + { + .type = "s35390a", + .addr = 0x30, + }, + + /* + * U9, TSC2007 Touch screen controller, address 0x49, irq RA6 + */ + { + .type = "tsc2007", + .addr = 0x49, + .irq = 46, + .platform_data = &ip7500iap_tsc2007_data, + }, +}; + +/* + * I2C bus on the board, SDA PE4, SCL PE5 + */ +static struct i2c_gpio_platform_data ip7500iap_i2c_data = { + .sda_pin = GPIO_RF_14, + .scl_pin = GPIO_RF_13, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .udelay = 50, +}; + +static struct platform_device ip7500iap_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ip7500iap_i2c_data, + }, +}; + +/****************************************************************************** + * Backlight on the board PD0, hardware PWM + */ +static struct ubicom32bl_platform_data ip7500iap_backlight_data = { + .type = UBICOM32BL_TYPE_PWM, + .pwm_channel = 2, + .pwm_prescale = 15, + .pwm_period = 60, + .default_intensity = 0x80, +}; + +static struct platform_device ip7500iap_backlight_device = { + .name = "ubicom32bl", + .id = -1, + .dev = { + .platform_data = &ip7500iap_backlight_data, + }, +}; + +/****************************************************************************** + * Devices on this board + */ +static struct platform_device *ip7500iap_devices[] __initdata = { + &ip7500iap_i2c_device, + &ip7500iap_backlight_device, +}; + +/* + * ip7500iap_power_off + * Called to turn the power off for this board + */ +static void ip7500iap_power_off(void) +{ + gpio_set_value(GPIO_RF_11, 0); +} + +/* + * ip7500iap_init + * Called to add the devices which we have on this board + */ +static int __init ip7500iap_init(void) +{ + struct platform_device *audio_dev; + struct platform_device *audio_dev2; + int ret; + + board_init(); + + ubi_gpio_init(); + + /* + * Hold the POWER_HOLD line + */ + ret = gpio_request(GPIO_RF_11, "POWER_HOLD"); + if (ret) { + printk(KERN_ERR "%s: could not request POWER_HOLD GPIO\n", __FUNCTION__); + } + gpio_direction_output(GPIO_RF_11, 1); + mach_power_off = ip7500iap_power_off; + + /* + * DAC nRESET line + */ + ret = gpio_request(GPIO_RE_7, "DAC_nRESET"); + if (ret) { + printk(KERN_ERR "%s: could not request DAC_nRESET GPIO\n", __FUNCTION__); + } + gpio_direction_output(GPIO_RE_7, 0); + udelay(1); + gpio_set_value(GPIO_RE_7, 1); + + /* + * Bring up any SDIO slots + */ + ip7500iap_portb_sd_init(); + ip7500iap_portf_sd_init(); + + /* + * Bring up audio devices + */ + platform_add_devices(ip7500iap_devices, ARRAY_SIZE(ip7500iap_devices)); + + audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0); + if (audio_dev) { + ip7500iap_i2c_board_info[0].platform_data = audio_dev; + } + + audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0); + if (audio_dev2) { + platform_device_register(audio_dev2); + } + + printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); + i2c_register_board_info(0, ip7500iap_i2c_board_info, ARRAY_SIZE(ip7500iap_i2c_board_info)); + + printk(KERN_INFO "IP7500 Internet Audio Player\n"); + + return 0; +} + +arch_initcall(ip7500iap_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500media.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500media.c new file mode 100644 index 000000000..3a51aec2a --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500media.c @@ -0,0 +1,732 @@ +/* + * arch/ubicom32/mach-ip7k/board-ip7500media.c + * Board file for IP7500 media board. + * + * Supports the following configuration + * CPU Module: + * P/N 8007-0510 rev 1.0 NOPHY + * P/N 8007-0511 rev 1.1 NOPHY + * DIP Switch SW2 configuration: + * POS 1: on = PCI enabled + * POS 2: off = TTYX => PF12 + * POS 3: off = TTYY => PF15 + * POS 4: unused + * Media Board: + * P/N 8007-0610 rev 1.0 + * + * LCD Adapter Board: (optional) + * P/N 8007-0920 rev 2.0 + * P/N 8007-0921 rev 2.1 + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/****************************************************************************** + * SD/IO Port F (Slot 1) platform data + */ +static struct resource ip7500media_portf_sd_resources[] = { + /* + * Send IRQ + */ + [0] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Receive IRQ + */ + [1] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Memory Mapped Registers + */ + [2] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct ubicom32sd_card ip7500media_portf_sd_cards[] = { + [0] = { + .pin_wp = IP7500MEDIA_IO16, + .wp_polarity = 1, + .pin_pwr = IP7500MEDIA_IO20, + .pin_cd = IP7500MEDIA_IO23, + }, + [1] = { + .pin_wp = IP7500MEDIA_IO17, + .wp_polarity = 1, + .pin_pwr = IP7500MEDIA_IO21, + .pin_cd = IP7500MEDIA_IO24, + }, +}; + +static struct ubicom32sd_platform_data ip7500media_portf_sd_platform_data = { + .ncards = 2, + .cards = ip7500media_portf_sd_cards, +}; + +static struct platform_device ip7500media_portf_sd_device = { + .name = "ubicom32sd", + .id = 0, + .resource = ip7500media_portf_sd_resources, + .num_resources = ARRAY_SIZE(ip7500media_portf_sd_resources), + .dev = { + .platform_data = &ip7500media_portf_sd_platform_data, + }, + +}; + +/* + * ip7500media_portf_sd_init + */ +static void ip7500media_portf_sd_init(void) +{ + /* + * Check the device tree for the sd_tio + */ + struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd"); + if (!sd_node) { + printk(KERN_INFO "PortF SDTIO not found\n"); + return; + } + + /* + * Fill in the resources and platform data from devtree information + */ + ip7500media_portf_sd_resources[0].start = sd_node->dn.sendirq; + ip7500media_portf_sd_resources[1].start = sd_node->dn.recvirq; + ip7500media_portf_sd_resources[2].start = (u32_t)&(sd_node->regs); + ip7500media_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); + + platform_device_register(&ip7500media_portf_sd_device); +} + +/****************************************************************************** + * SD/IO Port B (Slot 2) platform data + */ +static struct resource ip7500media_portb_sd_resources[] = { + /* + * Send IRQ + */ + [0] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Receive IRQ + */ + [1] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_IRQ, + }, + + /* + * Memory Mapped Registers + */ + [2] = { + /* + * The init routine will query the devtree and fill this in + */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct ubicom32sd_card ip7500media_portb_sd_cards[] = { + [0] = { + .pin_wp = IP7500MEDIA_IO19, + .wp_polarity = 1, + .pin_pwr = IP7500MEDIA_IO22, + .pin_cd = IP7500MEDIA_IO18, + }, +}; + +static struct ubicom32sd_platform_data ip7500media_portb_sd_platform_data = { + .ncards = 1, + .cards = ip7500media_portb_sd_cards, +}; + +static struct platform_device ip7500media_portb_sd_device = { + .name = "ubicom32sd", + .id = 1, + .resource = ip7500media_portb_sd_resources, + .num_resources = ARRAY_SIZE(ip7500media_portb_sd_resources), + .dev = { + .platform_data = &ip7500media_portb_sd_platform_data, + }, + +}; + +/* + * ip7500media_portb_sd_init + */ +static void ip7500media_portb_sd_init(void) +{ + /* + * Check the device tree for the sd_tio + */ + struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd"); + if (!sd_node) { + printk(KERN_INFO "PortB SDTIO not found\n"); + return; + } + + /* + * Fill in the resources and platform data from devtree information + */ + ip7500media_portb_sd_resources[0].start = sd_node->dn.sendirq; + ip7500media_portb_sd_resources[1].start = sd_node->dn.recvirq; + ip7500media_portb_sd_resources[2].start = (u32_t)&(sd_node->regs); + ip7500media_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); + + platform_device_register(&ip7500media_portb_sd_device); +} + +/* + * ip7500media_u17_setup + * Called by I2C to tell us that u17 is setup. + * + * This function is called by I2C to tell us that u17 has been setup. All + * devices which rely on this chip being initialized (or even present) need to + * be initialized in this function otherwise they may get initialized too early. + * + * Currently the only device depending on u17 is the SDIO + */ +static int __init ip7500media_u17_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *context) +{ + /* + * Initialize the Port F/Port B SD slots (only the enabled ports will init) + */ + ip7500media_portf_sd_init(); + ip7500media_portb_sd_init(); + + return 0; +} + +/****************************************************************************** + * LCD VGH on the board at PE6 + */ +static struct ubicom32lcdpower_platform_data ip7500media_lcdpower_data = { + .vgh_gpio = GPIO_RE_7, + .vgh_polarity = true, +}; + +static struct platform_device ip7500media_lcdpower_device = { + .name = "ubicom32lcdpower", + .id = -1, + .dev = { + .platform_data = &ip7500media_lcdpower_data, + }, +}; + +/****************************************************************************** + * Backlight on the board PD0, hardware PWM + */ +static struct ubicom32bl_platform_data ip7500media_backlight_data = { + .type = UBICOM32BL_TYPE_PWM, + .pwm_channel = 2, + .pwm_prescale = 15, + .pwm_period = 60, + .default_intensity = 0x80, +}; + +static struct platform_device ip7500media_backlight_device = { + .name = "ubicom32bl", + .id = -1, + .dev = { + .platform_data = &ip7500media_backlight_data, + }, +}; + +/****************************************************************************** + * Ubicom32Input on I2C, U15 MAX7310, address 0x18, 8 bits + */ +static struct ubicom32input_i2c_button ip7500media_ubicom32input_i2c_u15_buttons[] = { + { + .type = EV_KEY, + .code = KEY_LEFT, + .bit = 0, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_RIGHT, + .bit = 1, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_UP, + .bit = 2, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_DOWN, + .bit = 3, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_ENTER, + .bit = 4, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_MENU, + .bit = 5, + .active_low = 1, + }, + { + .type = EV_KEY, + .code = KEY_ESC, + .bit = 6, + .active_low = 1, + }, +}; + +static struct ubicom32input_i2c_platform_data ip7500media_ubicom32input_i2c_u15_platform_data = { + .buttons = ip7500media_ubicom32input_i2c_u15_buttons, + .nbuttons = ARRAY_SIZE(ip7500media_ubicom32input_i2c_u15_buttons), + .name = "Ubicom32 Input I2C U15", +}; + +/****************************************************************************** + * Additional GPIO chips + */ +static struct pca953x_platform_data ip7500media_gpio_u16_platform_data = { + .gpio_base = IP7500MEDIA_U16_BASE, +}; + +static struct pca953x_platform_data ip7500media_gpio_u17_platform_data = { + .gpio_base = IP7500MEDIA_U17_BASE, + .setup = ip7500media_u17_setup, +}; + +static struct pca953x_platform_data ip7500media_gpio_u18_platform_data = { + .gpio_base = IP7500MEDIA_U18_BASE, +}; + + +/****************************************************************************** + * Touch controller present on LCD Adapter board + * + * Connected via I2C bus, interrupt on PD1 + */ +#include + +/* + * ip7500media_tsc2007_exit_platform_hw + */ +static void ip7500media_tsc2007_exit_platform_hw(void) +{ + UBICOM32_IO_PORT(RD)->int_mask &= ~(1 << 11); + UBICOM32_IO_PORT(RD)->ctl2 &= ~(0x03 << 16); + gpio_free(GPIO_RD_1); +} + +/* + * ip7500media_tsc2007_init_platform_hw + */ +static int ip7500media_tsc2007_init_platform_hw(void) +{ + int res = gpio_request(GPIO_RD_1, "TSC2007_IRQ"); + if (res) { + return res; + } + UBICOM32_IO_PORT(RD)->function = 0; + UBICOM32_IO_PORT(RD)->int_mask = (1 << 11); + UBICOM32_IO_PORT(RD)->ctl2 &= ~(0x03 << 16); + UBICOM32_IO_PORT(RD)->ctl2 |= (0x02 << 16); + + return 0; +} + +/* + * ip7500media_tsc2007_clear_penirq + */ +static void ip7500media_tsc2007_clear_penirq(void) +{ + UBICOM32_IO_PORT(RD)->int_clr = (1 << 11); +} + +/* + * ip7500media_tsc2007_get_pendown_state + */ +static int ip7500media_tsc2007_get_pendown_state(void) +{ + return !gpio_get_value(GPIO_RD_1); +} + +static struct tsc2007_platform_data ip7500media_tsc2007_data = { + .model = 2007, + .x_plate_ohms = 350, + .get_pendown_state = ip7500media_tsc2007_get_pendown_state, + .init_platform_hw = ip7500media_tsc2007_init_platform_hw, + .exit_platform_hw = ip7500media_tsc2007_exit_platform_hw, + .clear_penirq = ip7500media_tsc2007_clear_penirq, +}; + +/****************************************************************************** + * Devices on the I2C bus + * + * BEWARE of changing the order of things in this array as we depend on + * certain things to be in certain places. + */ +static struct i2c_board_info __initdata ip7500media_i2c_board_info[] = { + /* + * U6, CS4350 DAC, address 0x4B + */ + { + .type = "cs4350", + .addr = 0x4B, + }, + + /* + * U14, S35390A RTC, address 0x30 + */ + { + .type = "s35390a", + .addr = 0x30, + }, + + /* + * U15, MAX7310 IO expander, 8 bits, address 0x18 + * IO0: User I/O (J16-1) (Left) IO4: User I/O (J16-5) (Enter) + * IO1: User I/O (J16-2) (Right) IO5: User I/O (J16-6) (Menu) + * IO2: User I/O (J16-3) (Up) IO6: User I/O (J16-7) (Back) + * IO3: User I/O (J16-4) (Down) IO7: User I/O (J16-8) + */ + { + .type = "ubicom32in_max7310", + .addr = 0x18, + .platform_data = &ip7500media_ubicom32input_i2c_u15_platform_data, + }, + + /* + * U16, MAX7310 IO expander, 8 bits, address 0x1C + * IO8 : User I/O (J16-9) IO12: User I/O (J16-17) + * IO9 : User I/O (J16-10) IO13: User I/O (J16-18) + * IO10: User I/O (J16-15) IO14: User I/O (J16-19) + * IO11: User I/O (J16-16) IO15: User I/O (J16-20) + */ + { + .type = "max7310", + .addr = 0x1C, + .platform_data = &ip7500media_gpio_u16_platform_data, + }, + + /* + * U17, MAX7310 IO expander, 8 bits, address 0x1A + * IO16: SDIO1A_WP IO20: SD1A_PWREN + * IO17: SDIO1B_WP IO21: SD1B_PWREN + * IO18: SDIO2_CD IO22: SD2_PWREN + * IO19: SDIO2_WP IO23: SDIO1A_CD + * + */ + { + .type = "max7310", + .addr = 0x1A, + .platform_data = &ip7500media_gpio_u17_platform_data, + }, + + /* + * U18, MAX7310 IOB expander, 8 bits, address 0x1E + * IO24: SDIO1B_CD IO28: User I/O TP6 + * IO25: User I/O TP9 IO29: User I/O TP5 + * IO26: User I/O TP8 IO30: User I/O TP4 + * IO27: User I/O TP7 IO31: User I/O TP3 + */ + { + .type = "max7310", + .addr = 0x1E, + .platform_data = &ip7500media_gpio_u18_platform_data, + }, +}; + +/* + * Additional I2C devices to add when a LCD adapter board is present + */ +static struct i2c_board_info __initdata ip7500media_lcd_adapter_i2c_board_info[] = { + { + I2C_BOARD_INFO("tsc2007", 0x48), + .irq = PORT_OTHER_INT(RD), + .platform_data = &ip7500media_tsc2007_data, + }, +}; + +/* + * I2C bus on the board, SDA PE4, SCL PE5 + */ +static struct i2c_gpio_platform_data ip7500media_i2c_data = { + .sda_pin = GPIO_RE_4, + .scl_pin = GPIO_RE_5, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .udelay = 50, +}; + +static struct platform_device ip7500media_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ip7500media_i2c_data, + }, +}; + +/* + * Virtual Frame Buffer device for use with LCD Adapter + */ +static struct platform_device ip7500media_vfb_device = { + .name = "ubicom32vfb", + .id = -1, +}; + +/* + * vdc_override: + * 0: no override (auto-detect) + * 1: force vdc usage + * 2: force lcd adapter usage + */ +static int __initdata vdc_override = 0; + +/* + * ip7500media_set_forcevdc + * Called when forcevdc is present on the kernel boot line + */ +static int __init ip7500media_set_forcevdc(char *str) +{ + if (str[0] == '1') { + vdc_override = 1; + } else { + vdc_override = 2; + } + return 1; +} + +/* + * ip7500media_video_init + * Called late to determine what kind of video we have on this board + */ +static int __init ip7500media_video_init(void) +{ + struct i2c_adapter *adap; + struct i2c_msg msg[1]; + unsigned char *data; + unsigned char checksum; + int err; + int i; + + if (vdc_override == 1) { + printk(KERN_INFO "Force VDCTIO mode\n"); + goto no_adapter; + } + if (vdc_override == 2) { + printk(KERN_INFO "Force LCD Adapter Board mode\n"); + return 0; + } + + /* + * Check to see if there is an EEPROM out there. If we see an + * EEPROM then we will assume a LCD Adapter Board (8007-092x) + * exists. + */ + data = kmalloc(256, GFP_KERNEL); + if (!data) { + printk(KERN_WARNING "%s: Failed to allocate memory\n", __FUNCTION__); + return -ENOMEM; + } + + adap = i2c_get_adapter(0); + if (!adap) { + printk(KERN_WARNING "%s: Failed to get i2c adapter\n", __FUNCTION__); + kfree(data); + return -ENODEV; + } + data[0] = 0; + msg->addr = 0x50; + msg->flags = 0; + msg->len = 1; + msg->buf = data; + err = i2c_transfer(adap, msg, 1); + if (err < 0) { + goto no_adapter; + } + + msg->addr = 0x50; + msg->flags = I2C_M_RD; + msg->len = 256; + msg->buf = data; + err = i2c_transfer(adap, msg, 1); + if (err < 0) { + goto no_adapter; + } + + i2c_put_adapter(adap); + + /* + * Verify the checksum + */ + checksum = 0xff; + for (i = 0; i < 255; i++) { + checksum ^= data[i]; + } + if (checksum != data[255]) { + printk(KERN_WARNING "%s: Checksum mismatch\n", __FUNCTION__); + } + + kfree(data); + + /* + * Bring up VFB + */ + platform_device_register(&ip7500media_vfb_device); + + /* + * Add the i2c devices on the LCD Adapter board. (We have to use i2c_new_device + * since it's late in the boot process.) + */ + printk(KERN_INFO "%s: registering LCD Adapter board i2c resources\n", __FUNCTION__); + for (i = 0; i < ARRAY_SIZE(ip7500media_lcd_adapter_i2c_board_info); i++) { + i2c_new_device(adap, &ip7500media_lcd_adapter_i2c_board_info[i]); + } + + i2c_put_adapter(adap); + + return 0; + + /* + * No LCD Adapter board, bring up VDC + */ +no_adapter: + vdc_tio_init(); + return 0; +} +late_initcall(ip7500media_video_init); +__setup("forcevdc=", ip7500media_set_forcevdc); + +/* + * ip7500media_init + * Called to add the devices which we have on this board + */ +static int __init ip7500media_init(void) +{ + struct platform_device *audio_dev; + int have_ethernet = (devtree_find_node("eth_lan") != 0); + + board_init(); + + ubi_gpio_init(); + +#ifdef CONFIG_UIO_UBICOM32RING + ring_tio_init("decoder_ring"); +#endif + + /* + * Register all of the devices we have on this board + */ + printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); + platform_device_register(&ip7500media_i2c_device); + platform_device_register(&ip7500media_backlight_device); + + /* + * If ethernet doesn't exist then we can init the lcdpower + */ + if (!have_ethernet) { + platform_device_register(&ip7500media_lcdpower_device); + } + + /* + * Allocate the audio drivers. SPDIF not supported on boards with ethernet. + */ + audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0); + if (audio_dev) { + ip7500media_i2c_board_info[0].platform_data = audio_dev; + } + + if (!have_ethernet) { + struct platform_device *audio_dev2; + + audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0); + if (audio_dev2) { + platform_device_register(audio_dev2); + } + } + + /* + * Register all of the devices which sit on the I2C bus + */ + printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); + i2c_register_board_info(0, ip7500media_i2c_board_info, ARRAY_SIZE(ip7500media_i2c_board_info)); + + /* + * We have to initialize the SDIO after the I2C IOB gets setup. SDIO is initialized in + * ip7500media_u17_setup + */ + + printk("IP7500 Media Board\n"); + + return 0; +} + +arch_initcall(ip7500media_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500module.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500module.c new file mode 100644 index 000000000..c8c223a9f --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500module.c @@ -0,0 +1,55 @@ +/* + * arch/ubicom32/mach-ip7k/board-ip7500module.c + * Support for IP7500 CPU module board. + * + * This file supports the IP7500 CPU module board: + * 8007-0510 Rev 1.0 + * 8007-0510A Rev 1.0 (with ethernet) + * + * DIP Switch SW2 configuration: (*) default + * POS 1: on(*) = PCI enabled, off = PCI disabled + * POS 2: on(*) = TTYX => PA6, off = TTYX => PF12 + * POS 3: on(*) = TTYY => PA7, off = TTYY => PF15 + * POS 4: unused + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include + +/* + * ip7500module_init + * Called to add the devices which we have on this board + */ +static int __init ip7500module_init(void) +{ + board_init(); + + ubi_gpio_init(); + + return 0; +} + +arch_initcall(ip7500module_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c new file mode 100644 index 000000000..7f27933fa --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c @@ -0,0 +1,101 @@ +/* + * arch/ubicom32/mach-ip7k/board-ip7500wspkr.c + * Support for IP7500 Wireless Speaker board. + * + * This file supports the IP7500 Wireless Speaker board: + * 8007-1210 Rev 1.0 + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#include +#include +#include + +#include +#include +#include +#include + +static struct i2c_board_info __initdata ip7500wspkr_i2c_board_info[] = { + /* + * U6, CS4350 DAC, address 0x4B + */ + { + .type = "cs4350", + .addr = 0x4B, + }, +}; + +/* + * I2C bus on the board, SDA PE4, SCL PE5 + */ +static struct i2c_gpio_platform_data ip7500wspkr_i2c_data = { + .sda_pin = GPIO_RD_5, + .scl_pin = GPIO_RD_6, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .udelay = 50, +}; + +static struct platform_device ip7500wspkr_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ip7500wspkr_i2c_data, + }, +}; + +static struct platform_device *ip7500wspkr_devices[] __initdata = { + &ip7500wspkr_i2c_device, +}; + +/* + * ip7500wspkr_init + * Called to add the devices which we have on this board + */ +static int __init ip7500wspkr_init(void) +{ + struct platform_device *audio_dev; + struct platform_device *audio_dev2; + + board_init(); + + ubi_gpio_init(); + + platform_add_devices(ip7500wspkr_devices, ARRAY_SIZE(ip7500wspkr_devices)); + + audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0); + if (audio_dev) { + ip7500wspkr_i2c_board_info[0].platform_data = audio_dev; + } + + audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0); + if (audio_dev2) { + platform_device_register(audio_dev2); + } + + printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); + i2c_register_board_info(0, ip7500wspkr_i2c_board_info, ARRAY_SIZE(ip7500wspkr_i2c_board_info)); + + printk(KERN_INFO "IP7500 Wireless Speaker Board\n"); + + return 0; +} + +arch_initcall(ip7500wspkr_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/Makefile b/target/linux/ubicom32/files/arch/ubicom32/mm/Makefile new file mode 100644 index 000000000..222128d2b --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mm/Makefile @@ -0,0 +1,32 @@ +# +# arch/ubicom32/mm/Makefile +# +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# +# +# Makefile for the linux m68knommu specific parts of the memory manager. +# + +obj-y += init.o fault.o memory.o kmap.o ocm-alloc.o diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/fault.c b/target/linux/ubicom32/files/arch/ubicom32/mm/fault.c new file mode 100644 index 000000000..ce6b1c760 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mm/fault.c @@ -0,0 +1,80 @@ +/* + * arch/ubicom32/mm/fault.c + * Ubicom32 architecture page fault implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1998 D. Jeff Dionne , + * Copyright (C) 2000 Lineo, Inc. (www.lineo.com) + * + * Based on: + * + * linux/arch/m68k/mm/fault.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include + +#include +#include + +extern void die_if_kernel(char *, struct pt_regs *, long); + +/* + * This routine handles page faults. It determines the problem, and + * then passes it off to one of the appropriate routines. + * + * error_code: + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * + * If this routine detects a bad access, it returns 1, otherwise it + * returns 0. + */ +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) +{ +#ifdef DEBUG + printk (KERN_DEBUG "regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n", + regs->sr, regs->pc, address, error_code); +#endif + + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long) address < PAGE_SIZE) { + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + } else + printk(KERN_ALERT "Unable to handle kernel access"); + printk(KERN_ALERT " at virtual address %08lx\n",address); + die_if_kernel("Oops", regs, error_code); + do_exit(SIGKILL); + + return 1; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/init.c b/target/linux/ubicom32/files/arch/ubicom32/mm/init.c new file mode 100644 index 000000000..c48683541 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mm/init.c @@ -0,0 +1,262 @@ +/* + * arch/ubicom32/mm/init.c + * Ubicom32 architecture virtual memory initialization. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 2000 Lineo, Inc. (www.lineo.com) + * + * Based on: + * + * linux/arch/m68k/mm/init.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com) + * DEC/2000 -- linux 2.4 support + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +extern void die_if_kernel(char *,struct pt_regs *,long); +extern void free_initmem(void); + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving a inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +static unsigned long empty_bad_page_table; + +static unsigned long empty_bad_page; + +unsigned long empty_zero_page; + +void show_mem(void) +{ + unsigned long i; + int free = 0, total = 0, reserved = 0, shared = 0; + int cached = 0; + + printk(KERN_INFO "\nMem-info:\n"); + show_free_areas(); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (!page_count(mem_map+i)) + free++; + else + shared += page_count(mem_map+i) - 1; + } + printk(KERN_INFO "%d pages of RAM\n",total); + printk(KERN_INFO "%d free pages\n",free); + printk(KERN_INFO "%d reserved pages\n",reserved); + printk(KERN_INFO "%d pages shared\n",shared); + printk(KERN_INFO "%d pages swap cached\n",cached); +} + +extern unsigned long memory_start; +extern unsigned long memory_end; +extern char __ocm_free_begin; +extern char __ocm_free_end; + +/* + * paging_init() continues the virtual memory environment setup which + * was begun by the code in arch/head.S. + * The parameters are pointers to where to stick the starting and ending + * addresses of available kernel virtual memory. + */ +void __init paging_init(void) +{ + /* + * Make sure start_mem is page aligned, otherwise bootmem and + * page_alloc get different views of the world. + */ +#ifdef DEBUG + unsigned long start_mem = PAGE_ALIGN(memory_start); +#endif + unsigned long end_mem = memory_end & PAGE_MASK; + +#ifdef DEBUG + printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n", + start_mem, end_mem); +#endif + + /* + * Initialize the bad page table and bad page to point + * to a couple of allocated pages. + */ + empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* + * TODO: enable setting up for user memory management interface. + */ + +#ifdef DEBUG + printk (KERN_DEBUG "before free_area_init\n"); + + printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n", + start_mem, end_mem); +#endif + + { + unsigned long zones_size[MAX_NR_ZONES] = {0, }; +#ifdef CONFIG_ZONE_DMA + zones_size[ZONE_DMA] = OCMSIZE >> PAGE_SHIFT; +#endif + zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT; +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = 0; +#endif + free_area_init(zones_size); + } +} + +void __init mem_init(void) +{ + int codek = 0, datak = 0, initk = 0; + unsigned long tmp, ram_start, ram_end, len; + extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end; + + unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */ + unsigned long end_mem = memory_end; /* DAVIDM - this must not include kernel stack at top */ + processor_dram(&ram_start, &ram_end); + len = (ram_end - ram_start) + OCMSIZE; +#ifdef DEBUG + printk(KERN_DEBUG "Mem_init: start=%lx, end=%lx\n", start_mem, end_mem); +#endif + + end_mem &= PAGE_MASK; + high_memory = (void *) end_mem; + + start_mem = PAGE_ALIGN(start_mem); + max_mapnr = num_physpages = (((unsigned long) high_memory) - PAGE_OFFSET) >> PAGE_SHIFT; + + /* this will put all memory onto the freelists */ +#ifdef CONFIG_ZONE_DMA + { + unsigned long ocm_free_begin = (unsigned long)&__ocm_free_begin; + unsigned long ocm_free_end = (unsigned long)&__ocm_free_end; + unsigned long zone_dma_begin = (ocm_free_begin + PAGE_SIZE - 1) & PAGE_MASK; + unsigned long zone_dma_end = ocm_free_end & PAGE_MASK; + if (zone_dma_end > zone_dma_begin) + free_bootmem(zone_dma_begin, zone_dma_end-zone_dma_begin); + } +#endif + totalram_pages = free_all_bootmem(); + + codek = (&_etext - &_stext) >> 10; + datak = (&_ebss - &_sdata) >> 10; + initk = (&__init_begin - &__init_end) >> 10; + + tmp = nr_free_pages() << PAGE_SHIFT; + printk(KERN_INFO "Memory available: %luk/%luk RAM, (%dk kernel code, %dk data)\n", + tmp >> 10, + len >> 10, + codek, + datak + ); + +} + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + int pages = 0; + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(virt_to_page(start)); + init_page_count(virt_to_page(start)); + free_page(start); + totalram_pages++; + pages++; + } + printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages); +} +#endif + +void +free_initmem() +{ +#ifdef CONFIG_RAMKERNEL + unsigned long addr; + extern char __init_begin, __init_end; + /* + * The following code should be cool even if these sections + * are not page aligned. + */ + addr = PAGE_ALIGN((unsigned long)(&__init_begin)); + /* next to check that the page we free is not a partial page */ + for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); + free_page(addr); + totalram_pages++; + } + printk(KERN_NOTICE "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n", + (addr - PAGE_ALIGN((long) &__init_begin)) >> 10, + (int)(PAGE_ALIGN((unsigned long)(&__init_begin))), + (int)(addr - PAGE_SIZE)); +#endif +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/kmap.c b/target/linux/ubicom32/files/arch/ubicom32/mm/kmap.c new file mode 100644 index 000000000..48b489ff1 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mm/kmap.c @@ -0,0 +1,79 @@ +/* + * arch/ubicom32/mm/kmap.c + * Ubicom32 architecture non-mmu ioremap and friends implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2000 Lineo, + * Copyright (C) 2000-2002 David McCullough + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +/* + * Map some physical address range into the kernel address space. + */ +void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) +{ + return (void *)physaddr; +} + +/* + * Unmap a ioremap()ed region again. + */ +void iounmap(void *addr) +{ +} + +/* + * __iounmap unmaps nearly everything, so be careful + * it doesn't free currently pointer/page tables anymore but it + * wans't used anyway and might be added later. + */ +void __iounmap(void *addr, unsigned long size) +{ +} + +/* + * Set new cache mode for some kernel address space. + * The caller must push data for that range itself, if such data may already + * be in the cache. + */ +void kernel_set_cachemode(void *addr, unsigned long size, int cmode) +{ +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/memory.c b/target/linux/ubicom32/files/arch/ubicom32/mm/memory.c new file mode 100644 index 000000000..17075ff53 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mm/memory.c @@ -0,0 +1,58 @@ +/* + * arch/ubicom32/mm/memory.c + * Ubicom32 architecture kernel_map() implementation. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 1998 Kenneth Albanowski , + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * + * Based on: + * + * linux/arch/m68k/mm/memory.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Map some physical address range into the kernel address space. + * The code is copied and adapted from map_chunk(). + */ + +unsigned long kernel_map(unsigned long paddr, unsigned long size, + int nocacheflag, unsigned long *memavailp ) +{ + return paddr; +} diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/ocm-alloc.c b/target/linux/ubicom32/files/arch/ubicom32/mm/ocm-alloc.c new file mode 100644 index 000000000..5a10c2938 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/mm/ocm-alloc.c @@ -0,0 +1,487 @@ +/* + * arch/ubicom32/mm/ocm-alloc.c + * OCM allocator for Uibcom32 On-Chip memory + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright 2004-2008 Analog Devices Inc. + * + * Based on: + * + * arch/blackfin/mm/sram-alloc.c + * + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt, a...) +#endif +/* + * the data structure for OCM heap pieces + */ +struct ocm_piece { + void *paddr; + int size; + pid_t pid; + struct ocm_piece *next; +}; + +/* + * struct ocm_heap + */ +struct ocm_heap { + struct ocm_piece free_head; + struct ocm_piece used_head; + struct mutex lock; +}; + +static struct ocm_heap ocm_inst_heap; +int ubi32_ocm_skbuf_max = 21, ubi32_ocm_skbuf, ubi32_ddr_skbuf; + +/* + * OCM area for storing code + */ +extern asmlinkage void *__ocm_free_begin; +extern asmlinkage void *__ocm_free_end; +extern asmlinkage void *__ocm_inst_heap_begin; +extern asmlinkage void *__ocm_inst_heap_end; +#define OCM_INST_HEAP_BEGIN ((unsigned int)&__ocm_inst_heap_begin) +#define OCM_INST_HEAP_END ((unsigned int)&__ocm_inst_heap_end) +#define OCM_INST_HEAP_LENGTH (OCM_INST_HEAP_END - OCM_INST_HEAP_BEGIN) + +static struct kmem_cache *ocm_piece_cache; + +/* + * _ocm_heap_init() + */ +static int __init _ocm_heap_init(struct ocm_heap *ocmh, + unsigned int start, + unsigned int size) +{ + ocmh->free_head.next = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL); + + if (!ocmh->free_head.next) + return -1; + + ocmh->free_head.next->paddr = (void *)start; + ocmh->free_head.next->size = size; + ocmh->free_head.next->pid = 0; + ocmh->free_head.next->next = 0; + + ocmh->used_head.next = NULL; + + /* mutex initialize */ + mutex_init(&ocmh->lock); + + return 0; +} + +/* + * _ocm_alloc_init() + * + * starts the ocm heap(s) + */ +static int __init _ocm_alloc_init(void) +{ + if (OCM_INST_HEAP_LENGTH) { + ocm_piece_cache = kmem_cache_create("ocm_piece_cache", + sizeof(struct ocm_piece), + 0, SLAB_PANIC, NULL); + + if (_ocm_heap_init(&ocm_inst_heap, + OCM_INST_HEAP_BEGIN, + OCM_INST_HEAP_LENGTH) == 0) + printk(KERN_INFO "OCM Instruction Heap %d KB\n", + OCM_INST_HEAP_LENGTH >> 10); + else + printk(KERN_INFO "Failed to initialize OCM " + "Instruction Heap\n"); + + } else + printk(KERN_INFO "No space available for OCM " + "Instruction Heap\n"); + + return 0; +} +pure_initcall(_ocm_alloc_init); + +/* + * _ocm_alloc() + * generic alloc a block in the ocm heap, if successful + * returns the pointer. + */ +static void *_ocm_alloc(size_t size, pid_t pid, struct ocm_heap *ocmheap) +{ + struct ocm_piece *pslot, *plast, *pavail; + struct ocm_piece *pfree_head = &ocmheap->free_head; + struct ocm_piece *pused_head = &ocmheap->used_head; + + if (size <= 0 || !pfree_head || !pused_head) + return NULL; + + /* Align the size */ + size = (size + 3) & ~3; + + pslot = pfree_head->next; + plast = pfree_head; + + /* + * search an available piece slot + */ + while (pslot != NULL && size > pslot->size) { + plast = pslot; + pslot = pslot->next; + } + + if (!pslot) + return NULL; + + if (pslot->size == size) { + /* + * Unlink this block from the list + */ + plast->next = pslot->next; + pavail = pslot; + } else { + /* + * Split this block in two. + */ + pavail = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL); + + if (!pavail) + return NULL; + + pavail->paddr = pslot->paddr; + pavail->size = size; + pslot->paddr += size; + pslot->size -= size; + } + + pavail->pid = pid; + + pslot = pused_head->next; + plast = pused_head; + + /* + * insert new piece into used piece list !!! + */ + while (pslot != NULL && pavail->paddr < pslot->paddr) { + plast = pslot; + pslot = pslot->next; + } + + pavail->next = pslot; + plast->next = pavail; + + DEBUGP("_ocm_alloc %d bytes at %p from in %p", + size, pavail->paddr, ocmheap); + + return pavail->paddr; +} + +#if 0 +/* Allocate the largest available block. */ +static void *_ocm_alloc_max(struct ocm_heap *ocmheap, + unsigned long *psize) +{ + struct ocm_piece *pfree_head = &ocmheap->free_head; + struct ocm_piece *pslot, *pmax; + + pmax = pslot = pfree_head->next; + + /* search an available piece slot */ + while (pslot != NULL) { + if (pslot->size > pmax->size) + pmax = pslot; + pslot = pslot->next; + } + + if (!pmax) + return NULL; + + *psize = pmax->size; + + return _ocm_alloc(*psize, ocmheap); +} +#endif + +/* + * _ocm_free() + * generic free a block in the ocm heap, if successful + */ +static int _ocm_free(const void *addr, + struct ocm_heap *ocmheap) +{ + struct ocm_piece *pslot, *plast, *pavail; + struct ocm_piece *pfree_head = &ocmheap->free_head; + struct ocm_piece *pused_head = &ocmheap->used_head; + + /* search the relevant memory slot */ + pslot = pused_head->next; + plast = pused_head; + + /* search an available piece slot */ + while (pslot != NULL && pslot->paddr != addr) { + plast = pslot; + pslot = pslot->next; + } + + if (!pslot) { + DEBUGP("_ocm_free %p not found in %p", addr, ocmheap); + return -1; + } + DEBUGP("_ocm_free %p from in %p", addr, ocmheap); + + plast->next = pslot->next; + pavail = pslot; + pavail->pid = 0; + + /* insert free pieces back to the free list */ + pslot = pfree_head->next; + plast = pfree_head; + + while (pslot != NULL && addr > pslot->paddr) { + plast = pslot; + pslot = pslot->next; + } + + if (plast != pfree_head && + plast->paddr + plast->size == pavail->paddr) { + plast->size += pavail->size; + kmem_cache_free(ocm_piece_cache, pavail); + } else { + pavail->next = plast->next; + plast->next = pavail; + plast = pavail; + } + + if (pslot && plast->paddr + plast->size == pslot->paddr) { + plast->size += pslot->size; + plast->next = pslot->next; + kmem_cache_free(ocm_piece_cache, pslot); + } + + return 0; +} + +/* + * ocm_inst_alloc() + * + * allocates a block of size in the ocm instrction heap, if + * successful returns address allocated. + */ +void *ocm_inst_alloc(size_t size, pid_t pid) +{ + void *addr; + + if (!OCM_INST_HEAP_LENGTH) + return NULL; + + + mutex_lock(&ocm_inst_heap.lock); + + addr = _ocm_alloc(size, pid, &ocm_inst_heap); + + mutex_unlock(&ocm_inst_heap.lock); + + return addr; +} +EXPORT_SYMBOL(ocm_inst_alloc); + +/* + * ocm_inst_free() + * free a block in the ocm instrction heap, returns 0 if successful. + */ +int ocm_inst_free(const void *addr) +{ + int ret; + + if (!OCM_INST_HEAP_LENGTH) + return -1; + + mutex_lock(&ocm_inst_heap.lock); + + ret = _ocm_free(addr, &ocm_inst_heap); + + mutex_unlock(&ocm_inst_heap.lock); + + return ret; +} +EXPORT_SYMBOL(ocm_inst_free); + +/* + * ocm_free() + * free a block in one of the ocm heaps, returns 0 if successful. + */ +int ocm_free(const void *addr) +{ + if (addr >= (void *)OCM_INST_HEAP_BEGIN + && addr < (void *)(OCM_INST_HEAP_END)) + return ocm_inst_free(addr); + else + return -1; +} +EXPORT_SYMBOL(ocm_free); + + +#ifdef CONFIG_PROC_FS +/* Need to keep line of output the same. Currently, that is 46 bytes + * (including newline). + */ +static int _ocm_proc_read(char *buf, int *len, int count, const char *desc, + struct ocm_heap *ocmheap) +{ + struct ocm_piece *pslot; + struct ocm_piece *pfree_head = &ocmheap->free_head; + struct ocm_piece *pused_head = &ocmheap->used_head; + + /* The format is the following + * --- OCM 123456789012345 Size PID State \n + * 12345678-12345678 1234567890 12345 1234567890\n + */ + int l; + l = sprintf(&buf[*len], "--- OCM %-15s Size PID State \n", + desc); + + *len += l; + count -= l; + + mutex_lock(&ocm_inst_heap.lock); + + /* + * search the relevant memory slot + */ + pslot = pused_head->next; + + while (pslot != NULL && count > 46) { + l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n", + pslot->paddr, pslot->paddr + pslot->size, + pslot->size, pslot->pid, "ALLOCATED"); + + *len += l; + count -= l; + pslot = pslot->next; + } + + pslot = pfree_head->next; + + while (pslot != NULL && count > 46) { + l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n", + pslot->paddr, pslot->paddr + pslot->size, + pslot->size, pslot->pid, "FREE"); + + *len += l; + count -= l; + pslot = pslot->next; + } + + mutex_unlock(&ocm_inst_heap.lock); + + return 0; +} + +static int ocm_proc_read(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + int len = 0; + + len = sprintf(&buf[len], "--- OCM SKB usage (max RX buf %d)\n" + "(SKB in OCM) %d - (SKB in DDR) %d\n", + ubi32_ocm_skbuf_max, + ubi32_ocm_skbuf, + ubi32_ddr_skbuf); + + len += sprintf(&buf[len], "--- OCM Data Heap Size\n" + "%p-%p %10i\n", + ((void *)&__ocm_free_begin), + ((void *)&__ocm_free_end), + ((unsigned int)&__ocm_free_end) - + ((unsigned int)&__ocm_free_begin)); + + if (_ocm_proc_read(buf, &len, count - len, "Inst Heap", + &ocm_inst_heap)) + goto not_done; + *eof = 1; + not_done: + return len; +} + +static int ocm_proc_write(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + int n, v; + char in[8]; + + if (count > sizeof(in)) + return -EINVAL; + + if (copy_from_user(in, buffer, count)) + return -EFAULT; + in[count-1] = 0; + + printk(KERN_INFO "OCM skb alloc max = %s\n", in); + + n = 0; + v = 0; + while ((in[n] >= '0') && (in[n] <= '9')) { + v = v * 10 + (int)(in[n] - '0'); + n++; + } + + if (v == 0) + return -EINVAL; + + ubi32_ocm_skbuf_max = v; + ubi32_ocm_skbuf = ubi32_ddr_skbuf = 0; + + return count; +} + +static int __init sram_proc_init(void) +{ + struct proc_dir_entry *ptr; + ptr = create_proc_entry("ocm", S_IFREG | S_IRUGO, NULL); + if (!ptr) { + printk(KERN_WARNING "unable to create /proc/ocm\n"); + return -1; + } + ptr->read_proc = ocm_proc_read; + ptr->write_proc = ocm_proc_write; + return 0; +} +late_initcall(sram_proc_init); +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/oprofile/Makefile b/target/linux/ubicom32/files/arch/ubicom32/oprofile/Makefile new file mode 100644 index 000000000..969d2f702 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/oprofile/Makefile @@ -0,0 +1,37 @@ +# +# arch/ubicom32/Makefile +# Makefile for Oprofile support on Ubicom32 +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# + +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) profile.o diff --git a/target/linux/ubicom32/files/arch/ubicom32/oprofile/ipProf.h b/target/linux/ubicom32/files/arch/ubicom32/oprofile/ipProf.h new file mode 100644 index 000000000..2a785f08d --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/oprofile/ipProf.h @@ -0,0 +1,39 @@ +#ifndef __IP_PROF_H__ +#define __IP_PROF_H__ + +/* This number MUST match what is used in the ultra configuration! */ +#define IPPROFILETIO_MAX_SAMPLES 600 + +/* Move to .h file used in both; avoid special types */ +struct profile_sample { + unsigned int pc; /* PC value */ + unsigned int parent; /* a5 contents, to find the caller */ + unsigned char cond_codes; /* for branch prediction */ + unsigned char thread; /* I-blocked, D-blocked, + 4-bit thread number */ + unsigned short active; /* which threads are active - + for accurate counting */ + unsigned short blocked; /* which threads are blocked due to + I or D cache misses */ + unsigned int latency; /* CPU clocks since the last message + dispatch in this thread + (thread 0 only for now) */ +}; + + +struct profilenode { + struct devtree_node dn; + volatile unsigned char enabled; /* Is the tio enabled to + take samples? */ + volatile unsigned char busy; /* set when the samples + are being read */ + volatile unsigned int mask; /* Threads that change the MT_EN flag */ + volatile unsigned short rate; /* What is the sampling rate? */ + volatile unsigned short head; /* sample taker puts samples here */ + volatile unsigned short tail; /* packet filler takes samples here */ + volatile unsigned short count; /* number of valid samples */ + volatile unsigned short total; /* Total samples */ + struct profile_sample samples[IPPROFILETIO_MAX_SAMPLES]; +}; + +#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/oprofile/profile.c b/target/linux/ubicom32/files/arch/ubicom32/oprofile/profile.c new file mode 100644 index 000000000..aeac3c666 --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/oprofile/profile.c @@ -0,0 +1,221 @@ +/* + * arch/ubicom32/oprofile/profile.c + * Oprofile support for arch Ubicom32 + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) + * any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, see + * . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +/** + * @file profile.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author Hunyue Yau + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* For identifying userland vs kernel address */ +#include +#include "ipProf.h" + +/* For communications with the backend */ +static struct profilenode *profile_node; + +/* Bitmask containing all Linux threads - as seen by the ROSR reg */ +static unsigned long th_all_mask; + +/* Lookup table to translate a hardware thread into a CPU identifier + * Table is indexed by the ROSR value which is assumed to be + * relatively small (0...15). + */ +unsigned int cpu_map[THREAD_ARCHITECTURAL_MAX]; + +static struct pt_regs regs; + +/* + * For each sample returned, checked to see if they are relevant to + * us. This is necessary as the ubicom32 architecture has other software + * running outside of Linux. Only then, put the sample into the relevant + * cpu bins. + * + * To minimize overhead, a global mask with all possible threads of in + * interest to us is used as a first check. Then a second mask identifying + * the thread is used to obtain an identifier for that "CPU". + */ + +/* + * ubicom32_build_cpu_th_mask() + * + * Build a lookup table for translation between hardware thread + * "ROSR" values and Linux CPU ids + * + * *** This gets executed on all CPUs at once! *** + */ +static void ubicom32_build_cpu_th_mask(void *mask) +{ + thread_t self = thread_get_self(); + unsigned long *th_m = mask; + + BUG_ON(self <= 0 || self >= THREAD_ARCHITECTURAL_MAX); + cpu_map[self] = smp_processor_id(); + + set_bit(self, th_m); +} + +/* + * profile_interrupt() + * + * Process samples returned from the profiler backend. The backend + * may return samples that are irrelevant to us or may even return + * multiple samples for the same CPU. Note that the sames may be + * for ANY cpu. At this time, this is unique and to support this requires + * Oprofile to expose an interface to accept the CPU that the same came + * frome. + */ +static irqreturn_t profile_interrupt(int irq, void *arg) +{ + int i, buf_entry; + int is_kernel; + unsigned int bit_th; + unsigned int th; + + if (!(profile_node->enabled) || profile_node->count < 0) { + printk(KERN_WARNING + "Unexpected interrupt, no samples or not enabled!\n"); + return IRQ_HANDLED; + } + + profile_node->busy = 1; /* Keep backend out */ + + for (i = 0; i < profile_node->count; i++) { + buf_entry = profile_node->tail; + profile_node->tail++; + profile_node->tail %= IPPROFILETIO_MAX_SAMPLES; + + /* Note - the "thread" ID is only the lower 4 bits */ + th = (0x0f & profile_node->samples[buf_entry].thread); + bit_th = (1 << th); + + if ((bit_th & th_all_mask) == 0) + continue; + + regs.pc = profile_node->samples[buf_entry].pc; + + is_kernel = ubicom32_is_kernel(regs.pc); + + oprofile_add_ext_sample_cpu(regs.pc, ®s, 0, is_kernel, + cpu_map[th]); + } + profile_node->count = 0; + profile_node->busy = 0; + + return IRQ_HANDLED; +} + +/* + * profile_start() + * + * Notification from oprofile to start the profiler + */ +static int profile_start(void) +{ + if (!profile_node) + return -1; + + profile_node->enabled = 1; + + return 0; +} + +/* + * profile_stop() + * + * Notification from oprofile to stop the profiler + */ +static void profile_stop(void) +{ + if (profile_node) + profile_node->enabled = 0; +} + +/* + * oprofile_arch_init() + * + * Attach to Oprofile after qualify the availability of the backend + * profiler support. + */ +int __init oprofile_arch_init(struct oprofile_operations *ops) +{ + int r = -ENODEV; + + profile_node = (struct profilenode *)devtree_find_node("profiler"); + + if (profile_node == NULL) { + printk(KERN_WARNING "Cannot find profiler node\n"); + return r; + } + + r = request_irq(profile_node->dn.recvirq, profile_interrupt, + IRQF_DISABLED, "profiler", NULL); + + if (r < 0) { + profile_node = NULL; + printk(KERN_WARNING "Cannot get profiler IRQ\n"); + return r; + } + + ops->start = profile_start; + ops->stop = profile_stop; + ops->cpu_type = "timer"; + + memset(cpu_map, 0, sizeof(cpu_map)); + + on_each_cpu(ubicom32_build_cpu_th_mask, &th_all_mask, 1); + + memset(®s, 0, sizeof(regs)); + + return r; +} + +/* + * oprofile_arch_exit() + * + * External call to take outselves out. + * Make sure backend is not running. + */ +void oprofile_arch_exit(void) +{ + BUG_ON(profile_node->enabled); +} diff --git a/target/linux/ubicom32/files/drivers/char/hw_random/ubicom32-rng.c b/target/linux/ubicom32/files/drivers/char/hw_random/ubicom32-rng.c new file mode 100644 index 000000000..e42958989 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/char/hw_random/ubicom32-rng.c @@ -0,0 +1,105 @@ +/* + * drivers/net/ubi32-eth.c + * Ubicom32 hardware random number generator driver. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "ubicom32_rng" + +static int ubicom32_rng_data_present(struct hwrng *rng, int wait) +{ + int data, i; + + for (i = 0; i < 20; i++) { + data = *(int *)(TIMER_BASE + TIMER_TRN); + if (data || !wait) + break; + udelay(10); + } + return data; +} + +static int ubicom32_rng_data_read(struct hwrng *rng, u32 *data) +{ + *data = *(int *)(TIMER_BASE + TIMER_TRN); + return 4; +} + +static int ubicom32_rng_init(struct hwrng *rng) +{ + printk(KERN_INFO "ubicom32 rng init\n"); + *(int *)(TIMER_BASE + TIMER_TRN_CFG) = TIMER_TRN_CFG_ENABLE_OSC; + return 0; +} + +static void ubicom32_rng_cleanup(struct hwrng *rng) +{ + printk(KERN_INFO "ubicom32 rng cleanup\n"); + *(int *)(TIMER_BASE + TIMER_TRN_CFG) = 0; +} + +static struct hwrng ubicom32_rng = { + .name = MODULE_NAME, + .init = ubicom32_rng_init, + .cleanup = ubicom32_rng_cleanup, + .data_present = ubicom32_rng_data_present, + .data_read = ubicom32_rng_data_read, + .priv = 0, +}; + +static int __init mod_init(void) +{ + int err; + + printk(KERN_INFO "ubicom32 rng started\n"); + err = hwrng_register(&ubicom32_rng); + if (err) { + printk(KERN_ERR "ubicom32 rng register failed (%d)\n", + err); + } + + return err; +} + +static void __exit mod_exit(void) +{ + printk(KERN_INFO "ubicom32 rng stopped\n"); + hwrng_unregister(&ubicom32_rng); +} + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ubicom, Inc."); +MODULE_DESCRIPTION("H/W rng driver for ubicom32 processor"); +MODULE_VERSION("1:1.0.a"); diff --git a/target/linux/ubicom32/files/drivers/mmc/host/ubicom32sd.c b/target/linux/ubicom32/files/drivers/mmc/host/ubicom32sd.c new file mode 100644 index 000000000..107c92a74 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/mmc/host/ubicom32sd.c @@ -0,0 +1,773 @@ +/* + * drivers/mmc/host/ubicom32sd.c + * Ubicom32 Secure Digital Host Controller Interface driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "ubicom32sd" + +#define sd_printk(...) +//#define sd_printk printk + +#define SDTIO_VP_VERSION 3 + +#define SDTIO_MAX_SG_BLOCKS 16 + +enum sdtio_commands { + SDTIO_COMMAND_NOP, + SDTIO_COMMAND_SETUP, + SDTIO_COMMAND_SETUP_SDIO, + SDTIO_COMMAND_EXECUTE, + SDTIO_COMMAND_RESET, +}; + +#define SDTIO_COMMAND_SHIFT 24 +#define SDTIO_COMMAND_FLAG_STOP_RSP_CRC (1 << 10) +#define SDTIO_COMMAND_FLAG_STOP_RSP_136 (1 << 9) +#define SDTIO_COMMAND_FLAG_STOP_RSP (1 << 8) +#define SDTIO_COMMAND_FLAG_STOP_CMD (1 << 7) +#define SDTIO_COMMAND_FLAG_DATA_STREAM (1 << 6) +#define SDTIO_COMMAND_FLAG_DATA_RD (1 << 5) +#define SDTIO_COMMAND_FLAG_DATA_WR (1 << 4) +#define SDTIO_COMMAND_FLAG_CMD_RSP_CRC (1 << 3) +#define SDTIO_COMMAND_FLAG_CMD_RSP_136 (1 << 2) +#define SDTIO_COMMAND_FLAG_CMD_RSP (1 << 1) +#define SDTIO_COMMAND_FLAG_CMD (1 << 0) + +/* + * SDTIO_COMMAND_SETUP_SDIO + */ +#define SDTIO_COMMAND_FLAG_SDIO_INT_EN (1 << 0) + +/* + * SDTIO_COMMAND_SETUP + * clock speed in arg + */ +#define SDTIO_COMMAND_FLAG_4BIT (1 << 3) +#define SDTIO_COMMAND_FLAG_1BIT (1 << 2) +#define SDTIO_COMMAND_FLAG_SET_CLOCK (1 << 1) +#define SDTIO_COMMAND_FLAG_SET_WIDTH (1 << 0) + +#define SDTIO_COMMAND_FLAG_CMD_RSP_MASK (SDTIO_COMMAND_FLAG_CMD_RSP | SDTIO_COMMAND_FLAG_CMD_RSP_136) +#define SDTIO_COMMAND_FLAG_STOP_RSP_MASK (SDTIO_COMMAND_FLAG_STOP_RSP | SDTIO_COMMAND_FLAG_STOP_RSP_136) +#define SDTIO_COMMAND_FLAG_RSP_MASK (SDTIO_COMMAND_FLAG_CMD_RSP_MASK | SDTIO_COMMAND_FLAG_STOP_RSP_MASK) + +struct sdtio_vp_sg { + volatile void *addr; + volatile u32_t len; +}; + +#define SDTIO_VP_INT_STATUS_DONE (1 << 31) +#define SDTIO_VP_INT_STATUS_SDIO_INT (1 << 10) +#define SDTIO_VP_INT_STATUS_DATA_CRC_ERR (1 << 9) +#define SDTIO_VP_INT_STATUS_DATA_PROG_ERR (1 << 8) +#define SDTIO_VP_INT_STATUS_DATA_TIMEOUT (1 << 7) +#define SDTIO_VP_INT_STATUS_STOP_RSP_CRC (1 << 6) +#define SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT (1 << 5) +#define SDTIO_VP_INT_STATUS_CMD_RSP_CRC (1 << 4) +#define SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT (1 << 3) +#define SDTIO_VP_INT_STATUS_CMD_TIMEOUT (1 << 2) +#define SDTIO_VP_INT_STATUS_CARD1_INSERT (1 << 1) +#define SDTIO_VP_INT_STATUS_CARD0_INSERT (1 << 0) + +struct sdtio_vp_regs { + u32_t version; + u32_t f_max; + u32_t f_min; + + volatile u32_t int_status; + + volatile u32_t command; + volatile u32_t arg; + + volatile u32_t cmd_opcode; + volatile u32_t cmd_arg; + volatile u32_t cmd_rsp0; + volatile u32_t cmd_rsp1; + volatile u32_t cmd_rsp2; + volatile u32_t cmd_rsp3; + + volatile u32_t stop_opcode; + volatile u32_t stop_arg; + volatile u32_t stop_rsp0; + volatile u32_t stop_rsp1; + volatile u32_t stop_rsp2; + volatile u32_t stop_rsp3; + + volatile u32_t data_timeout_ns; + volatile u16_t data_blksz; + volatile u16_t data_blkct; + volatile u32_t data_bytes_transferred; + volatile u32_t sg_len; + struct sdtio_vp_sg sg[SDTIO_MAX_SG_BLOCKS]; +}; + +struct ubicom32sd_data { + const struct ubicom32sd_platform_data *pdata; + + struct mmc_host *mmc; + + /* + * Lock used to protect the data structure + spinlock_t lock; + */ + int int_en; + int int_pend; + + /* + * Receive and transmit interrupts used for communicating + * with hardware + */ + int irq_tx; + int irq_rx; + + /* + * Current outstanding mmc request + */ + struct mmc_request *mrq; + + /* + * Hardware registers + */ + struct sdtio_vp_regs *regs; +}; + +/*****************************************************************************\ + * * + * Suspend/resume * + * * +\*****************************************************************************/ + +#if 0//def CONFIG_PM + +int ubicom32sd_suspend_host(struct ubicom32sd_host *host, pm_message_t state) +{ + int ret; + + ret = mmc_suspend_host(host->mmc, state); + if (ret) + return ret; + + free_irq(host->irq, host); + + return 0; +} + +EXPORT_SYMBOL_GPL(ubicom32sd_suspend_host); + +int ubicom32sd_resume_host(struct ubicom32sd_host *host) +{ + int ret; + + if (host->flags & UBICOM32SD_USE_DMA) { + if (host->ops->enable_dma) + host->ops->enable_dma(host); + } + + ret = request_irq(host->irq, ubicom32sd_irq, IRQF_SHARED, + mmc_hostname(host->mmc), host); + if (ret) + return ret; + + ubicom32sd_init(host); + mmiowb(); + + ret = mmc_resume_host(host->mmc); + if (ret) + return ret; + + return 0; +} + +EXPORT_SYMBOL_GPL(ubicom32sd_resume_host); + +#endif /* CONFIG_PM */ + +/* + * ubicom32sd_send_command_sync + */ +static void ubicom32sd_send_command_sync(struct ubicom32sd_data *ud, u32_t command, u32_t arg) +{ + ud->regs->command = command; + ud->regs->arg = arg; + ubicom32_set_interrupt(ud->irq_tx); + while (ud->regs->command) { + ndelay(100); + } +} + +/* + * ubicom32sd_send_command + */ +static void ubicom32sd_send_command(struct ubicom32sd_data *ud, u32_t command, u32_t arg) +{ + ud->regs->command = command; + ud->regs->arg = arg; + ubicom32_set_interrupt(ud->irq_tx); +} + +/* + * ubicom32sd_reset + */ +static void ubicom32sd_reset(struct ubicom32sd_data *ud) +{ + ubicom32sd_send_command_sync(ud, SDTIO_COMMAND_RESET << SDTIO_COMMAND_SHIFT, 0); + ud->regs->int_status = 0; +} + +/* + * ubicom32sd_mmc_request + */ +static void ubicom32sd_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); + u32_t command = SDTIO_COMMAND_EXECUTE << SDTIO_COMMAND_SHIFT; + int ret = 0; + + WARN(ud->mrq != NULL, "ud->mrq still set to %p\n", ud->mrq); + //pr_debug("send cmd %08x arg %08x flags %08x\n", cmd->opcode, cmd->arg, cmd->flags); + + if (mrq->cmd) { + struct mmc_command *cmd = mrq->cmd; + + sd_printk("%s:\t\t\tsetup cmd %02d arg %08x flags %08x\n", mmc_hostname(mmc), cmd->opcode, cmd->arg, cmd->flags); + + ud->regs->cmd_opcode = cmd->opcode; + ud->regs->cmd_arg = cmd->arg; + + command |= SDTIO_COMMAND_FLAG_CMD; + + if (cmd->flags & MMC_RSP_PRESENT) { + command |= SDTIO_COMMAND_FLAG_CMD_RSP; + } + + if (cmd->flags & MMC_RSP_136) { + command |= SDTIO_COMMAND_FLAG_CMD_RSP_136; + } + + if (cmd->flags & MMC_RSP_CRC) { + command |= SDTIO_COMMAND_FLAG_CMD_RSP_CRC; + } + } + + if (mrq->data) { + struct mmc_data *data = mrq->data; + struct scatterlist *sg = data->sg; + int i; + +printk("%s:\t\t\tsetup data blksz %d num %d sglen=%d fl=%08x Tns=%u\n", mmc_hostname(mmc), data->blksz, data->blocks, data->sg_len, data->flags, data->timeout_ns); + + sd_printk("%s:\t\t\tsetup data blksz %d num %d sglen=%d fl=%08x Tns=%u\n", + mmc_hostname(mmc), data->blksz, data->blocks, data->sg_len, + data->flags, data->timeout_ns); + + if (data->sg_len > SDTIO_MAX_SG_BLOCKS) { + ret = -EINVAL; + data->error = -EINVAL; + goto fail; + } + + ud->regs->data_timeout_ns = data->timeout_ns; + ud->regs->data_blksz = data->blksz; + ud->regs->data_blkct = data->blocks; + ud->regs->sg_len = data->sg_len; + + /* + * Load all of our sg list into the driver sg buffer + */ + for (i = 0; i < data->sg_len; i++) { + sd_printk("%s: sg %d = %p %d\n", mmc_hostname(mmc), i, sg_virt(sg), sg->length); + ud->regs->sg[i].addr = sg_virt(sg); + ud->regs->sg[i].len = sg->length; + if (((u32_t)ud->regs->sg[i].addr & 0x03) || (sg->length & 0x03)) { + sd_printk("%s: Need aligned buffers\n", mmc_hostname(mmc)); + ret = -EINVAL; + data->error = -EINVAL; + goto fail; + } + sg++; + } + if (data->flags & MMC_DATA_READ) { + command |= SDTIO_COMMAND_FLAG_DATA_RD; + } else if (data->flags & MMC_DATA_WRITE) { + command |= SDTIO_COMMAND_FLAG_DATA_WR; + } else if (data->flags & MMC_DATA_STREAM) { + command |= SDTIO_COMMAND_FLAG_DATA_STREAM; + } + } + + if (mrq->stop) { + struct mmc_command *stop = mrq->stop; + sd_printk("%s: \t\t\tsetup stop %02d arg %08x flags %08x\n", mmc_hostname(mmc), stop->opcode, stop->arg, stop->flags); + + ud->regs->stop_opcode = stop->opcode; + ud->regs->stop_arg = stop->arg; + + command |= SDTIO_COMMAND_FLAG_STOP_CMD; + + if (stop->flags & MMC_RSP_PRESENT) { + command |= SDTIO_COMMAND_FLAG_STOP_RSP; + } + + if (stop->flags & MMC_RSP_136) { + command |= SDTIO_COMMAND_FLAG_STOP_RSP_136; + } + + if (stop->flags & MMC_RSP_CRC) { + command |= SDTIO_COMMAND_FLAG_STOP_RSP_CRC; + } + } + + ud->mrq = mrq; + + sd_printk("%s: Sending command %08x\n", mmc_hostname(mmc), command); + + ubicom32sd_send_command(ud, command, 0); + + return; +fail: + sd_printk("%s: mmcreq ret = %d\n", mmc_hostname(mmc), ret); + mrq->cmd->error = ret; + mmc_request_done(mmc, mrq); +} + +/* + * ubicom32sd_mmc_set_ios + */ +static void ubicom32sd_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); + u32_t command = SDTIO_COMMAND_SETUP << SDTIO_COMMAND_SHIFT; + u32_t arg = 0; + sd_printk("%s: ios call bw:%u pm:%u clk:%u\n", mmc_hostname(mmc), 1 << ios->bus_width, ios->power_mode, ios->clock); + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_1BIT; + break; + + case MMC_BUS_WIDTH_4: + command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_4BIT; + break; + } + + if (ios->clock) { + arg = ios->clock; + command |= SDTIO_COMMAND_FLAG_SET_CLOCK; + } + + switch (ios->power_mode) { + + /* + * Turn off the SD bus (power + clock) + */ + case MMC_POWER_OFF: + gpio_set_value(ud->pdata->cards[0].pin_pwr, !ud->pdata->cards[0].pwr_polarity); + command |= SDTIO_COMMAND_FLAG_SET_CLOCK; + break; + + /* + * Turn on the power to the SD bus + */ + case MMC_POWER_ON: + gpio_set_value(ud->pdata->cards[0].pin_pwr, ud->pdata->cards[0].pwr_polarity); + break; + + /* + * Turn on the clock to the SD bus + */ + case MMC_POWER_UP: + /* + * Done above + */ + break; + } + + ubicom32sd_send_command_sync(ud, command, arg); + + /* + * Let the power settle down + */ + udelay(500); +} + +/* + * ubicom32sd_mmc_get_cd + */ +static int ubicom32sd_mmc_get_cd(struct mmc_host *mmc) +{ + struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); + sd_printk("%s: get cd %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_cd, gpio_get_value(ud->pdata->cards[0].pin_cd)); + + return gpio_get_value(ud->pdata->cards[0].pin_cd) ? + ud->pdata->cards[0].cd_polarity : + !ud->pdata->cards[0].cd_polarity; +} + +/* + * ubicom32sd_mmc_get_ro + */ +static int ubicom32sd_mmc_get_ro(struct mmc_host *mmc) +{ + struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); + sd_printk("%s: get ro %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_wp, gpio_get_value(ud->pdata->cards[0].pin_wp)); + + return gpio_get_value(ud->pdata->cards[0].pin_wp) ? + ud->pdata->cards[0].wp_polarity : + !ud->pdata->cards[0].wp_polarity; +} + +/* + * ubicom32sd_mmc_enable_sdio_irq + */ +static void ubicom32sd_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); + + ud->int_en = enable; + if (enable && ud->int_pend) { + ud->int_pend = 0; + mmc_signal_sdio_irq(mmc); + } +} + +/* + * ubicom32sd_interrupt + */ +static irqreturn_t ubicom32sd_interrupt(int irq, void *dev) +{ + struct mmc_host *mmc = (struct mmc_host *)dev; + struct mmc_request *mrq; + struct ubicom32sd_data *ud; + u32_t int_status; + + if (!mmc) { + return IRQ_HANDLED; + } + + ud = (struct ubicom32sd_data *)mmc_priv(mmc); + if (!ud) { + return IRQ_HANDLED; + } + + int_status = ud->regs->int_status; + ud->regs->int_status &= ~int_status; + + if (int_status & SDTIO_VP_INT_STATUS_SDIO_INT) { + if (ud->int_en) { + ud->int_pend = 0; + mmc_signal_sdio_irq(mmc); + } else { + ud->int_pend++; + } + } + + if (!(int_status & SDTIO_VP_INT_STATUS_DONE)) { + return IRQ_HANDLED; + } + + mrq = ud->mrq; + if (!mrq) { + sd_printk("%s: Spurious interrupt", mmc_hostname(mmc)); + return IRQ_HANDLED; + } + ud->mrq = NULL; + + /* + * SDTIO_VP_INT_DONE + */ + if (mrq->cmd->flags & MMC_RSP_PRESENT) { + struct mmc_command *cmd = mrq->cmd; + cmd->error = 0; + + if ((cmd->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_CRC)) { + cmd->error = -EILSEQ; + } else if (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT) { + cmd->error = -ETIMEDOUT; + goto done; + } else if (cmd->flags & MMC_RSP_136) { + cmd->resp[0] = ud->regs->cmd_rsp0; + cmd->resp[1] = ud->regs->cmd_rsp1; + cmd->resp[2] = ud->regs->cmd_rsp2; + cmd->resp[3] = ud->regs->cmd_rsp3; + } else { + cmd->resp[0] = ud->regs->cmd_rsp0; + } + sd_printk("%s:\t\t\tResponse %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); + } + + if (mrq->data) { + struct mmc_data *data = mrq->data; + + if (int_status & SDTIO_VP_INT_STATUS_DATA_TIMEOUT) { + data->error = -ETIMEDOUT; + sd_printk("%s:\t\t\tData Timeout\n", mmc_hostname(mmc)); + goto done; + } else if (int_status & SDTIO_VP_INT_STATUS_DATA_CRC_ERR) { + data->error = -EILSEQ; + sd_printk("%s:\t\t\tData CRC\n", mmc_hostname(mmc)); + goto done; + } else if (int_status & SDTIO_VP_INT_STATUS_DATA_PROG_ERR) { + data->error = -EILSEQ; + sd_printk("%s:\t\t\tData Program Error\n", mmc_hostname(mmc)); + goto done; + } else { + data->error = 0; + data->bytes_xfered = ud->regs->data_bytes_transferred; + } + } + + if (mrq->stop && (mrq->stop->flags & MMC_RSP_PRESENT)) { + struct mmc_command *stop = mrq->stop; + stop->error = 0; + + if ((stop->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_CRC)) { + stop->error = -EILSEQ; + } else if (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT) { + stop->error = -ETIMEDOUT; + goto done; + } else if (stop->flags & MMC_RSP_136) { + stop->resp[0] = ud->regs->stop_rsp0; + stop->resp[1] = ud->regs->stop_rsp1; + stop->resp[2] = ud->regs->stop_rsp2; + stop->resp[3] = ud->regs->stop_rsp3; + } else { + stop->resp[0] = ud->regs->stop_rsp0; + } + sd_printk("%s:\t\t\tStop Response %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), stop->resp[0], stop->resp[1], stop->resp[2], stop->resp[3], stop->error); + } + +done: + mmc_request_done(mmc, mrq); + + return IRQ_HANDLED; +} + +static struct mmc_host_ops ubicom32sd_ops = { + .request = ubicom32sd_mmc_request, + .set_ios = ubicom32sd_mmc_set_ios, + .get_ro = ubicom32sd_mmc_get_ro, + .get_cd = ubicom32sd_mmc_get_cd, + .enable_sdio_irq = ubicom32sd_mmc_enable_sdio_irq, +}; + +/* + * ubicom32sd_probe + */ +static int __devinit ubicom32sd_probe(struct platform_device *pdev) +{ + struct ubicom32sd_platform_data *pdata = (struct ubicom32sd_platform_data *)pdev->dev.platform_data; + struct mmc_host *mmc; + struct ubicom32sd_data *ud; + struct resource *res_regs; + struct resource *res_irq_tx; + struct resource *res_irq_rx; + int ret; + + /* + * Get our resources, regs is the hardware driver base address + * and the tx and rx irqs are used to communicate with the + * hardware driver. + */ + res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!res_regs || !res_irq_tx || !res_irq_rx) { + ret = -EINVAL; + goto fail; + } + + /* + * Reserve any gpios we need + */ + ret = gpio_request(pdata->cards[0].pin_wp, "sd-wp"); + if (ret) { + goto fail; + } + gpio_direction_input(pdata->cards[0].pin_wp); + + ret = gpio_request(pdata->cards[0].pin_cd, "sd-cd"); + if (ret) { + goto fail_cd; + } + gpio_direction_input(pdata->cards[0].pin_cd); + + /* + * HACK: for the dual port controller on port F, we don't support the second port right now + */ + if (pdata->ncards > 1) { + ret = gpio_request(pdata->cards[1].pin_pwr, "sd-pwr"); + gpio_direction_output(pdata->cards[1].pin_pwr, !pdata->cards[1].pwr_polarity); + gpio_direction_output(pdata->cards[1].pin_pwr, pdata->cards[1].pwr_polarity); + } + + ret = gpio_request(pdata->cards[0].pin_pwr, "sd-pwr"); + if (ret) { + goto fail_pwr; + } + gpio_direction_output(pdata->cards[0].pin_pwr, !pdata->cards[0].pwr_polarity); + + /* + * Allocate the MMC driver, it includes memory for our data. + */ + mmc = mmc_alloc_host(sizeof(struct ubicom32sd_data), &pdev->dev); + if (!mmc) { + ret = -ENOMEM; + goto fail_mmc; + } + ud = (struct ubicom32sd_data *)mmc_priv(mmc); + ud->mmc = mmc; + ud->pdata = pdata; + ud->regs = (struct sdtio_vp_regs *)res_regs->start; + ud->irq_tx = res_irq_tx->start; + ud->irq_rx = res_irq_rx->start; + platform_set_drvdata(pdev, mmc); + + ret = request_irq(ud->irq_rx, ubicom32sd_interrupt, IRQF_DISABLED, mmc_hostname(mmc), mmc); + if (ret) { + goto fail_mmc; + } + + /* + * Fill in the mmc structure + */ + mmc->ops = &ubicom32sd_ops; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL | MMC_CAP_SDIO_IRQ | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; + + mmc->f_min = ud->regs->f_min; + mmc->f_max = ud->regs->f_max; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + + /* + * Setup some restrictions on transfers + * + * We allow up to SDTIO_MAX_SG_BLOCKS of data to DMA into, there are + * not really any "max_seg_size", "max_req_size", or "max_blk_count" + * restrictions (must be less than U32_MAX though), pick + * something large?!... + * + * The hardware can do up to 4095 bytes per block, since the spec + * only requires 2048, we'll set it to that and not worry about + * potential weird blk lengths. + */ + mmc->max_hw_segs = SDTIO_MAX_SG_BLOCKS; + mmc->max_phys_segs = SDTIO_MAX_SG_BLOCKS; + mmc->max_seg_size = 1024 * 1024; + mmc->max_req_size = 1024 * 1024; + mmc->max_blk_count = 1024; + + mmc->max_blk_size = 2048; + + ubicom32sd_reset(ud); + + /* + * enable interrupts + */ + ud->int_en = 0; + ubicom32sd_send_command_sync(ud, SDTIO_COMMAND_SETUP_SDIO << SDTIO_COMMAND_SHIFT | SDTIO_COMMAND_FLAG_SDIO_INT_EN, 0); + + mmc_add_host(mmc); + + printk(KERN_INFO "%s at %p, irq %d/%d\n", mmc_hostname(mmc), + ud->regs, ud->irq_tx, ud->irq_rx); + return 0; + +fail_mmc: + gpio_free(pdata->cards[0].pin_pwr); +fail_pwr: + gpio_free(pdata->cards[0].pin_cd); +fail_cd: + gpio_free(pdata->cards[0].pin_wp); +fail: + return ret; +} + +/* + * ubicom32sd_remove + */ +static int __devexit ubicom32sd_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (mmc) { + struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); + + gpio_free(ud->pdata->cards[0].pin_pwr); + gpio_free(ud->pdata->cards[0].pin_cd); + gpio_free(ud->pdata->cards[0].pin_wp); + + mmc_remove_host(mmc); + mmc_free_host(mmc); + } + + /* + * Note that our data is allocated as part of the mmc structure + * so we don't need to free it. + */ + return 0; +} + +static struct platform_driver ubicom32sd_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = ubicom32sd_probe, + .remove = __devexit_p(ubicom32sd_remove), +#if 0 + .suspend = ubicom32sd_suspend, + .resume = ubicom32sd_resume, +#endif +}; + +/* + * ubicom32sd_init + */ +static int __init ubicom32sd_init(void) +{ + return platform_driver_register(&ubicom32sd_driver); +} +module_init(ubicom32sd_init); + +/* + * ubicom32sd_exit + */ +static void __exit ubicom32sd_exit(void) +{ + platform_driver_unregister(&ubicom32sd_driver); +} +module_exit(ubicom32sd_exit); + +MODULE_AUTHOR("Patrick Tjin"); +MODULE_DESCRIPTION("Ubicom32 Secure Digital Host Controller Interface driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/drivers/mtd/devices/nand-spi-er.c b/target/linux/ubicom32/files/drivers/mtd/devices/nand-spi-er.c new file mode 100644 index 000000000..73938c882 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/mtd/devices/nand-spi-er.c @@ -0,0 +1,1017 @@ +/* + * Micron SPI-ER NAND Flash Memory + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define NAND_SPI_ER_BLOCK_FROM_ROW(row) (row >> 6) + +#define NAND_SPI_ER_STATUS_P_FAIL (1 << 3) +#define NAND_SPI_ER_STATUS_E_FAIL (1 << 2) +#define NAND_SPI_ER_STATUS_OIP (1 << 0) + +#define NAND_SPI_ER_LAST_ROW_INVALID 0xFFFFFFFF +#define NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET 0x08 + +struct nand_spi_er_device { + const char *name; + + uint8_t id0; + uint8_t id1; + + unsigned int blocks; + unsigned int pages_per_block; + unsigned int page_size; + unsigned int write_size; + unsigned int erase_size; +}; + +struct nand_spi_er { + char name[24]; + + const struct nand_spi_er_device *device; + + struct mutex lock; + struct spi_device *spi; + + struct mtd_info mtd; + + unsigned int last_row; /* the last row we fetched */ + + /* + * Bad block table (MUST be last in strcuture) + */ + unsigned long nbb; + unsigned long bbt[0]; +}; + +const struct nand_spi_er_device nand_spi_er_devices[] = { + { + name: "MT29F1G01ZDC", + id0: 0x2C, + id1: 0x12, + blocks: 1024, + pages_per_block: 64, + page_size: 2048, + write_size: 512, + erase_size: 64 * 2048, + }, + { + name: "MT29F1G01ZDC", + id0: 0x2C, + id1: 0x13, + blocks: 1024, + pages_per_block: 64, + page_size: 2048, + write_size: 512, + erase_size: 64 * 2048, + }, +}; + +static int read_only = 0; +module_param(read_only, int, 0); +MODULE_PARM_DESC(read_only, "Leave device locked"); + +/* + * nand_spi_er_get_feature + * Get Feature register + */ +static int nand_spi_er_get_feature(struct nand_spi_er *chip, int reg, uint8_t *data) +{ + uint8_t txbuf[2]; + uint8_t rxbuf[1]; + int res; + + txbuf[0] = 0x0F; + txbuf[1] = reg; + res = spi_write_then_read(chip->spi, txbuf, 2, rxbuf, 1); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed get feature res=%d\n", chip->name, res); + return res; + } + *data = rxbuf[0]; + return 0; +} + +/* + * nand_spi_er_busywait + * Wait until the chip is not busy + */ +static int nand_spi_er_busywait(struct nand_spi_er *chip, uint8_t *data) +{ + int i; + + for (i = 0; i < 100; i++) { + int res = nand_spi_er_get_feature(chip, 0xC0, data); + if (res) { + return res; + } + if (!(*data & NAND_SPI_ER_STATUS_OIP)) { + break; + } + } + + return 0; +} + +/* + * nand_spi_er_erase + * Erase a block, parameters must be block aligned + */ +static int nand_spi_er_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct nand_spi_er *chip = mtd->priv; + struct spi_device *spi = chip->spi; + uint8_t txbuf[4]; + int res; + + DEBUG(MTD_DEBUG_LEVEL3, "%s: erase addr:%x len:%x\n", chip->name, instr->addr, instr->len); + + if ((instr->addr + instr->len) > mtd->size) { + return -EINVAL; + } + + if (instr->addr & (chip->device->erase_size - 1)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: erase address is not aligned %x\n", chip->name, instr->addr); + return -EINVAL; + } + + if (instr->len & (chip->device->erase_size - 1)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: erase len is not aligned %x\n", chip->name, instr->len); + return -EINVAL; + } + + mutex_lock(&chip->lock); + chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; + + while (instr->len) { + uint32_t block = instr->addr >> 17; + uint32_t row = block << 6; + uint8_t stat; + DEBUG(MTD_DEBUG_LEVEL3, "%s: block erase row:%x block:%x addr:%x rem:%x\n", chip->name, row, block, instr->addr, instr->len); + + /* + * Write enable + */ + txbuf[0] = 0x06; + res = spi_write(spi, txbuf, 1); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res); + mutex_unlock(&chip->lock); + return res; + } + + /* + * Test for bad block + */ + if (test_bit(block, chip->bbt)) { + instr->fail_addr = block << 17; + instr->state = MTD_ERASE_FAILED; + res = -EBADMSG; + goto done; + } + + /* + * Block erase + */ + txbuf[0] = 0xD8; + txbuf[1] = 0x00; + txbuf[2] = row >> 8; + txbuf[3] = row & 0xFF; + res = spi_write(spi, txbuf, 4); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed block erase res=%d\n", chip->name, res); + instr->fail_addr = block << 17; + instr->state = MTD_ERASE_FAILED; + goto done; + } + + /* + * Wait + */ + res = nand_spi_er_busywait(chip, &stat); + if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { + instr->fail_addr = block << 17; + instr->state = MTD_ERASE_FAILED; + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); + if (res) { + goto done; + } + + /* + * Chip is stuck? + */ + res = -EIO; + goto done; + } + + /* + * Check the status register + */ + if (stat & NAND_SPI_ER_STATUS_E_FAIL) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: E_FAIL signalled (%02x)\n", chip->name, stat); + instr->fail_addr = block << 17; + instr->state = MTD_ERASE_FAILED; + goto done; + } + + /* + * Next + */ + block++; + instr->len -= chip->device->erase_size; + instr->addr += chip->device->erase_size; + } + + instr->state = MTD_ERASE_DONE; + + mutex_unlock(&chip->lock); + return 0; + +done: + /* + * Write disable + */ + txbuf[0] = 0x04; + res = spi_write(spi, txbuf, 1); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res); + } + + mutex_unlock(&chip->lock); + + mtd_erase_callback(instr); + return 0; +} + +/* + * nand_spi_er_read + * + * return -EUCLEAN: ecc error recovered + * return -EBADMSG: ecc error not recovered +*/ +static int nand_spi_er_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct nand_spi_er *chip = mtd->priv; + struct spi_device *spi = chip->spi; + + uint32_t row; + uint32_t column; + int retval = 0; + + *retlen = 0; + DEBUG(MTD_DEBUG_LEVEL2, "%s: read block from %llx len %d into %p\n", chip->name, from, len, buf); + + /* + * Zero length reads, nothing to do + */ + if (len == 0) { + return 0; + } + + /* + * Reject reads which go over the end of the flash + */ + if ((from + len) > mtd->size) { + return -EINVAL; + } + + /* + * Get the row and column address to start at + */ + row = from >> 11; + column = from & 0x7FF; + DEBUG(MTD_DEBUG_LEVEL3, "%s: row=%x %d column=%x %d last_row=%x %d\n", chip->name, row, row, column, column, chip->last_row, chip->last_row); + + /* + * Read the data from the chip + */ + mutex_lock(&chip->lock); + while (len) { + uint8_t stat; + uint8_t txbuf[4]; + struct spi_message message; + struct spi_transfer x[2]; + int res; + size_t toread; + + /* + * Figure out how much to read + * + * If we are reading from the middle of a page then the most we + * can read is to the end of the page + */ + toread = len; + if (toread > (chip->device->page_size - column)) { + toread = chip->device->page_size - column; + } + + DEBUG(MTD_DEBUG_LEVEL3, "%s: buf=%p toread=%x row=%x column=%x last_row=%x\n", chip->name, buf, toread, row, column, chip->last_row); + + if (chip->last_row != row) { + /* + * Check if the block is bad + */ + if (test_bit(NAND_SPI_ER_BLOCK_FROM_ROW(row), chip->bbt)) { + mutex_unlock(&chip->lock); + return -EBADMSG; + } + + /* + * Load the appropriate page + */ + txbuf[0] = 0x13; + txbuf[1] = 0x00; + txbuf[2] = row >> 8; + txbuf[3] = row & 0xFF; + res = spi_write(spi, txbuf, 4); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed page load res=%d\n", chip->name, res); + mutex_unlock(&chip->lock); + return res; + } + + /* + * Wait + */ + res = nand_spi_er_busywait(chip, &stat); + if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); + if (res) { + mutex_unlock(&chip->lock); + return res; + } + + /* + * Chip is stuck? + */ + mutex_unlock(&chip->lock); + return -EIO; + } + + /* + * Check the ECC bits + */ + stat >>= 4; + if (stat == 1) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: ECC recovered, row=%x\n", chip->name, row); + retval = -EUCLEAN; + } + if (stat == 2) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: failed ECC, row=%x\n", chip->name, row); + chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; + mutex_unlock(&chip->lock); + return -EBADMSG; + } + + } + + chip->last_row = row; + + /* + * Read out the data + */ + spi_message_init(&message); + memset(x, 0, sizeof(x)); + + txbuf[0] = 0x03; + txbuf[1] = column >> 8; + txbuf[2] = column & 0xFF; + txbuf[3] = 0; + x[0].tx_buf = txbuf; + x[0].len = 4; + spi_message_add_tail(&x[0], &message); + + x[1].rx_buf = buf; + x[1].len = toread; + spi_message_add_tail(&x[1], &message); + + res = spi_sync(spi, &message); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed data read res=%d\n", chip->name, res); + mutex_unlock(&chip->lock); + return res; + } + buf += toread; + len -= toread; + *retlen += toread; + + /* + * For the next page, increment the row and always start at column 0 + */ + column = 0; + row++; + } + + mutex_unlock(&chip->lock); + return retval; +} + +/* + * nand_spi_er_write + */ +#define NOT_ALIGNED(x) ((x & (device->write_size - 1)) != 0) +static int nand_spi_er_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct nand_spi_er *chip = mtd->priv; + struct spi_device *spi = chip->spi; + const struct nand_spi_er_device *device = chip->device; + uint32_t row; + uint32_t col; + uint8_t txbuf[4]; + int res; + size_t towrite; + + DEBUG(MTD_DEBUG_LEVEL2, "%s: write block to %llx len %d from %p\n", chip->name, to, len, buf); + + *retlen = 0; + + /* + * nothing to write + */ + if (!len) { + return 0; + } + + /* + * Reject writes which go over the end of the flash + */ + if ((to + len) > mtd->size) { + return -EINVAL; + } + + /* + * Check to see if everything is page aligned + */ + if (NOT_ALIGNED(to) || NOT_ALIGNED(len)) { + printk(KERN_NOTICE "nand_spi_er_write: Attempt to write non page aligned data\n"); + return -EINVAL; + } + + mutex_lock(&chip->lock); + chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; + + /* + * If the first write is a partial write then write at most the number of + * bytes to get us page aligned and then the remainder will be + * page aligned. The last bit may be a partial page as well. + */ + col = to & (device->page_size - 1); + towrite = device->page_size - col; + if (towrite > len) { + towrite = len; + } + + /* + * Write the data + */ + row = to >> 11; + while (len) { + struct spi_message message; + struct spi_transfer x[2]; + uint8_t stat; + + DEBUG(MTD_DEBUG_LEVEL3, "%s: write %p to row:%x col:%x len:%x rem:%x\n", chip->name, buf, row, col, towrite, len); + + /* + * Write enable + */ + txbuf[0] = 0x06; + res = spi_write(spi, txbuf, 1); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res); + mutex_unlock(&chip->lock); + return res; + } + + /* + * Write the data into the cache + */ + spi_message_init(&message); + memset(x, 0, sizeof(x)); + txbuf[0] = 0x02; + txbuf[1] = col >> 8; + txbuf[2] = col & 0xFF; + x[0].tx_buf = txbuf; + x[0].len = 3; + spi_message_add_tail(&x[0], &message); + x[1].tx_buf = buf; + x[1].len = towrite; + spi_message_add_tail(&x[1], &message); + res = spi_sync(spi, &message); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed cache write res=%d\n", chip->name, res); + goto done; + } + + /* + * Program execute + */ + txbuf[0] = 0x10; + txbuf[1] = 0x00; + txbuf[2] = row >> 8; + txbuf[3] = row & 0xFF; + res = spi_write(spi, txbuf, 4); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed prog execute res=%d\n", chip->name, res); + goto done; + } + + /* + * Wait + */ + res = nand_spi_er_busywait(chip, &stat); + if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); + if (res) { + goto done; + } + + /* + * Chip is stuck? + */ + res = -EIO; + goto done; + } + + if (stat & (1 << 3)) { + res = -EBADMSG; + goto done; + } + + row++; + buf += towrite; + len -= towrite; + *retlen += towrite; + + /* + * At this point, we are always page aligned so start at column 0. + * Note we may not have a full page to write at the end, hence the + * check if towrite > len. + */ + col = 0; + towrite = device->page_size; + if (towrite > len) { + towrite = len; + } + } + + mutex_unlock(&chip->lock); + return res; + +done: + /* + * Write disable + */ + txbuf[0] = 0x04; + res = spi_write(spi, txbuf, 1); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res); + } + + mutex_unlock(&chip->lock); + + return res; +} + +/* + * nand_spi_er_isbad + */ +static int nand_spi_er_isbad(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_spi_er *chip = mtd->priv; + uint32_t block; + + if (ofs & (chip->device->erase_size - 1)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs); + return -EINVAL; + } + + block = ofs >> 17; + + return test_bit(block, chip->bbt); +} + +/* + * nand_spi_er_markbad + */ +static int nand_spi_er_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_spi_er *chip = mtd->priv; + struct spi_device *spi = chip->spi; + uint32_t block; + uint32_t row; + uint8_t txbuf[7]; + int res; + uint8_t stat; + + if (ofs & (chip->device->erase_size - 1)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs); + return -EINVAL; + } + + block = ofs >> 17; + + /* + * If it's already marked bad, no need to mark it + */ + if (test_bit(block, chip->bbt)) { + return 0; + } + + /* + * Mark it in our cache + */ + __set_bit(block, chip->bbt); + + /* + * Write the user bad block mark. If it fails, then we really + * can't do anything about it. + */ + mutex_lock(&chip->lock); + chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; + + /* + * Write enable + */ + txbuf[0] = 0x06; + res = spi_write(spi, txbuf, 1); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res); + mutex_unlock(&chip->lock); + return res; + } + + /* + * Write the mark + */ + txbuf[0] = 0x84; + txbuf[1] = 0x08; + txbuf[2] = NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET; + txbuf[3] = 0xde; + txbuf[4] = 0xad; + txbuf[5] = 0xbe; + txbuf[6] = 0xef; + res = spi_write(spi, txbuf, 7); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write mark res=%d\n", chip->name, res); + goto done; + } + + /* + * Program execute + */ + row = ofs >> 11; + txbuf[0] = 0x10; + txbuf[1] = 0x00; + txbuf[2] = row >> 8; + txbuf[3] = row & 0xFF; + res = spi_write(spi, txbuf, 4); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed program execute res=%d\n", chip->name, res); + goto done; + } + + /* + * Wait + */ + res = nand_spi_er_busywait(chip, &stat); + if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); + if (res) { + goto done; + } + + /* + * Chip is stuck? + */ + res = -EIO; + goto done; + } + + if (stat & (1 << 3)) { + res = -EBADMSG; + } + +done: + /* + * Write disable + */ + txbuf[0] = 0x04; + res = spi_write(spi, txbuf, 1); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res); + } + + mutex_unlock(&chip->lock); + + return res; +} + +/* + * nand_spi_er_read_bbt + */ +static int nand_spi_er_read_bbt(struct nand_spi_er *chip) +{ + int j; + for (j = 0; j < chip->device->blocks; j++) { + uint8_t txbuf[4]; + uint8_t rxbuf[16]; + uint32_t bbmark; + int res; + unsigned short row = j << 6; + uint8_t stat; + + /* + * Read Page + */ + txbuf[0] = 0x13; + txbuf[1] = 0x00; + txbuf[2] = row >> 8; + txbuf[3] = row & 0xFF; + res = spi_write(chip->spi, txbuf, 4); + if (res) { + return res; + } + + /* + * Wait + */ + res = nand_spi_er_busywait(chip, &stat); + if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); + if (res) { + return res; + } + + /* + * Chip is stuck? + */ + return -EIO; + } + + /* + * Check factory bad block mark + */ + txbuf[0] = 0x03; + txbuf[1] = 0x08; + txbuf[2] = 0x00; + txbuf[3] = 0x00; + res = spi_write_then_read(chip->spi, txbuf, 4, rxbuf, 16); + if (res) { + return res; + } + if (rxbuf[0] != 0xFF) { + chip->nbb++; + __set_bit(j, chip->bbt); + continue; + } + + memcpy(&bbmark, &rxbuf[8], 4); + if (bbmark == 0xdeadbeef) { + chip->nbb++; + __set_bit(j, chip->bbt); + } + } + +#if defined(CONFIG_MTD_DEBUG) && (MTD_DEBUG_LEVEL3 <= CONFIG_MTD_DEBUG_VERBOSE) + printk("%s: Bad Block Table:", chip->name); + for (j = 0; j < chip->device->blocks; j++) { + if ((j % 64) == 0) { + printk("\n%s: block %03x: ", chip->name, j); + } + printk("%c", test_bit(j, chip->bbt) ? 'X' : '.'); + } + printk("\n%s: Bad Block Numbers: ", chip->name); + for (j = 0; j < chip->device->blocks; j++) { + if (test_bit(j, chip->bbt)) { + printk("%x ", j); + } + } + printk("\n"); +#endif + + return 0; +} + +#ifndef MODULE +/* + * Called at boot time: + * + * nand_spi_er=read_only + * if read_only specified then do not unlock device + */ +static int __init nand_spi_er_setup(char *str) +{ + if (str && (strncasecmp(str, "read_only", 9) == 0)) { + read_only = 1; + } + return 0; +} + +__setup("nand_spi_er=", nand_spi_er_setup); +#endif + +/* + * nand_spi_er_probe + * Detect and initialize nand_spi_er device. + */ +static int __devinit nand_spi_er_probe(struct spi_device *spi) +{ + uint8_t txbuf[3]; + uint8_t rxbuf[2]; + int i; + int res; + size_t bbt_bytes; + struct nand_spi_er *chip; + const struct nand_spi_er_device *device; + + res = spi_setup(spi); + if (res) { + return res; + } + + /* + * Reset + */ + for (i = 0; i < 2; i++) { + txbuf[0] = 0xFF; + res = spi_write(spi, txbuf, 1); + if (res) { + return res; + } + udelay(250); + } + udelay(1000); + + /* + * Read ID + */ + txbuf[0] = 0x9F; + txbuf[1] = 0x00; + res = spi_write_then_read(spi, txbuf, 2, rxbuf, 2); + if (res) { + return res; + } + + device = nand_spi_er_devices; + for (i = 0; i < ARRAY_SIZE(nand_spi_er_devices); i++) { + if ((device->id0 == rxbuf[0]) && (device->id1 == rxbuf[1])) { + break; + } + device++; + } + if (i == ARRAY_SIZE(nand_spi_er_devices)) { + return -ENODEV; + } + + /* + * Initialize our chip structure + */ + bbt_bytes = DIV_ROUND_UP(device->blocks, BITS_PER_BYTE); + chip = kzalloc(sizeof(struct nand_spi_er) + bbt_bytes, GFP_KERNEL); + if (!chip) { + return -ENOMEM; + } + snprintf(chip->name, sizeof(chip->name), "%s.%d.%d", device->name, spi->master->bus_num, spi->chip_select); + + chip->spi = spi; + chip->device = device; + chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; + + mutex_init(&chip->lock); + + chip->mtd.type = MTD_NANDFLASH; + chip->mtd.flags = MTD_WRITEABLE; + + /* + * #blocks * block size * n blocks + */ + chip->mtd.size = device->blocks * device->pages_per_block * device->page_size; + chip->mtd.erasesize = device->erase_size; + + /* + * 1 page, optionally we can support partial write (512) + */ + chip->mtd.writesize = device->write_size; + chip->mtd.name = device->name; + chip->mtd.erase = nand_spi_er_erase; + chip->mtd.read = nand_spi_er_read; + chip->mtd.write = nand_spi_er_write; + chip->mtd.block_isbad = nand_spi_er_isbad; + chip->mtd.block_markbad = nand_spi_er_markbad; + chip->mtd.priv = chip; + + /* + * Cache the bad block table + */ + res = nand_spi_er_read_bbt(chip); + if (res) { + kfree(chip); + return res; + } + + /* + * Un/lock the chip + */ + txbuf[0] = 0x1F; + txbuf[1] = 0xA0; + if (read_only) { + txbuf[2] = 0x38; + } else { + txbuf[2] = 0x00; + } + res = spi_write(spi, txbuf, 3); + if (res) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: failed lock operation res=%d\n", chip->name, res); + mutex_unlock(&chip->lock); + return res; + } + + spi_set_drvdata(spi, chip); + + printk(KERN_INFO "%s: added device %s size: %u KBytes %u bad blocks %s\n", spi->dev.bus_id, chip->mtd.name, DIV_ROUND_UP(chip->mtd.size, 1024), chip->nbb, read_only ? "[read only]" : ""); + return add_mtd_device(&chip->mtd); +} + +/* + * nand_spi_er_remove + */ +static int __devexit nand_spi_er_remove(struct spi_device *spi) +{ + struct nand_spi_er *chip = spi_get_drvdata(spi); + int status = 0; + + DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", spi->dev.bus_id); + status = del_mtd_device(&chip->mtd); + if (status == 0) + kfree(chip); + return status; +} + +static struct spi_driver nand_spi_er_driver = { + .driver = { + .name = "nand-spi-er", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = nand_spi_er_probe, + .remove = __devexit_p(nand_spi_er_remove), + + /* FIXME: investigate suspend and resume... */ +}; + +/* + * nand_spi_er_init + */ +static int __init nand_spi_er_init(void) +{ + return spi_register_driver(&nand_spi_er_driver); +} +module_init(nand_spi_er_init); + +/* + * nand_spi_er_exit + */ +static void __exit nand_spi_er_exit(void) +{ + spi_unregister_driver(&nand_spi_er_driver); +} +module_exit(nand_spi_er_exit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick Tjin"); +MODULE_DESCRIPTION("MTD nand_spi_er driver"); diff --git a/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-m25p80.c b/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-m25p80.c new file mode 100644 index 000000000..405491cc4 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-m25p80.c @@ -0,0 +1,1066 @@ +/* + * drivers/mtd/devices/ubi32-m25p80.c + * NOR flash driver, Ubicom processor internal SPI flash interface. + * + * This code instantiates the serial flash that contains the + * original bootcode. The serial flash start at address 0x60000000 + * in both Ubicom32V3 and Ubicom32V4 ISAs. + * + * This piece of flash is made to appear as a Memory Technology + * Device (MTD) with this driver to allow Read/Write/Erase operations. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define UBICOM32_FLASH_BASE 0x60000000 +#define UBICOM32_FLASH_MAX_SIZE 0x01000000 +#define UBICOM32_FLASH_START 0x00000000 +#define UBICOM32_KERNEL_OFFSET 0x00010000 /* The kernel starts after Ubicom + * .protect section. */ + +static struct mtd_partition ubicom32_flash_partitions[] = { + { + .name = "Bootloader", /* Protected Section + * Partition */ + .size = 0x10000, + .offset = UBICOM32_FLASH_START, +// .mask_flags = MTD_WRITEABLE /* Mark Read-only */ + }, + { + .name = "Kernel", /* Kernel Partition. */ + .size = 0, /* this will be set up during + * probe stage. At that time we + * will know end of linux image + * in flash. */ + .offset = MTDPART_OFS_APPEND, /* Starts right after Protected + * section. */ +// .mask_flags = MTD_WRITEABLE /* Mark Read-only */ + }, + { + .name = "Rest", /* Rest of the flash. */ + .size = 0x200000, /* Use up what remains in the + * flash. */ + .offset = MTDPART_OFS_NXTBLK, /* Starts right after Protected + * section. */ + } +}; + +static struct flash_platform_data ubicom32_flash_data = { + .name = "ubicom32_boot_flash", + .parts = ubicom32_flash_partitions, + .nr_parts = ARRAY_SIZE(ubicom32_flash_partitions), +}; + +static struct resource ubicom32_flash_resource[] = { + { + .start = UBICOM32_FLASH_BASE, + .end = UBICOM32_FLASH_BASE + + UBICOM32_FLASH_MAX_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ubicom32_flash_device = { + .name = "ubicom32flashdriver", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(ubicom32_flash_resource), + .resource = ubicom32_flash_resource, + .dev = { + .platform_data = &ubicom32_flash_data, + }, +}; + +static struct platform_device *ubicom32_flash_devices[] = { + &ubicom32_flash_device, +}; + +static int __init ubicom32_flash_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", + __FUNCTION__); + platform_add_devices(ubicom32_flash_devices, + ARRAY_SIZE(ubicom32_flash_devices)); + return 0; +} + +arch_initcall(ubicom32_flash_init); + +/* + * MTD SPI driver for ST M25Pxx (and similar) serial flash chips through + * Ubicom32 SPI controller. + * + * Author: Mike Lavender, mike@steroidmicros.com + * + * Copyright (c) 2005, Intec Automation Inc. + * + * Some parts are based on lart.c by Abraham Van Der Merwe + * + * Cleaned up and generalized based on mtd_dataflash.c + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#define FLASH_PAGESIZE 256 + +/* Flash opcodes. */ +#define OPCODE_WREN 0x06 /* Write enable */ +#define OPCODE_RDSR 0x05 /* Read status register */ +#define OPCODE_READ 0x03 /* Read data bytes (low frequency) */ +#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ +#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ +#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ +#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ +#define OPCODE_RDID 0x9f /* Read JEDEC ID */ + +/* Status Register bits. */ +#define SR_WIP 1 /* Write in progress */ +#define SR_WEL 2 /* Write enable latch */ +/* meaning of other SR_* bits may differ between vendors */ +#define SR_BP0 4 /* Block protect 0 */ +#define SR_BP1 8 /* Block protect 1 */ +#define SR_BP2 0x10 /* Block protect 2 */ +#define SR_SRWD 0x80 /* SR write protect */ + +/* Define max times to check status register before we give up. */ +#define MAX_READY_WAIT_COUNT 100000 + + +#ifdef CONFIG_MTD_PARTITIONS +#define mtd_has_partitions() (1) +#else +#define mtd_has_partitions() (0) +#endif + +/* + * Ubicom32 FLASH Command Set + */ +#define FLASH_FC_INST_CMD 0x00 /* for SPI command only transaction */ +#define FLASH_FC_INST_WR 0x01 /* for SPI write transaction */ +#define FLASH_FC_INST_RD 0x02 /* for SPI read transaction */ + +#define ALIGN_DOWN(v, a) ((v) & ~((a) - 1)) +#define ALIGN_UP(v, a) (((v) + ((a) - 1)) & ~((a) - 1)) + +#define FLASH_COMMAND_KICK_OFF(io) \ + asm volatile( \ + " bset "D(IO_INT_CLR)"(%0), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" \ + " jmpt.t .+4 \n\t" \ + " bset "D(IO_INT_SET)"(%0), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" \ + : \ + : "a" (io) \ + : "memory", "cc" \ + ); + +#define FLASH_COMMAND_WAIT_FOR_COMPLETION(io) \ + asm volatile( \ + " btst "D(IO_INT_STATUS)"(%0), #%%bit("D(IO_XFL_INT_DONE)") \n\t" \ + " jmpeq.f .-4 \n\t" \ + : \ + : "a" (io) \ + : "memory", "cc" \ + ); + +#define FLASH_COMMAND_EXEC(io) \ + FLASH_COMMAND_KICK_OFF(io) \ + FLASH_COMMAND_WAIT_FOR_COMPLETION(io) + + +#define OSC1_FREQ 12000000 +#define TEN_MICRO_SECONDS (OSC1_FREQ * 10 / 1000000) + +/* + * We will have to eventually replace this null definition with the real thing. + */ +#define WATCHDOG_RESET() + +#define EXTFLASH_WRITE_FIFO_SIZE 32 +#define EXTFLASH_WRITE_BLOCK_SIZE EXTFLASH_WRITE_FIFO_SIZE /* limit the size to + * FIFO capacity, so + * the thread can be + * suspended. */ + +#define JFFS2_FILESYSTEM_SIZE 0x100000 + +/****************************************************************************/ + +struct m25p { + struct platform_device *plt_dev; + struct mutex lock; + struct mtd_info mtd; + unsigned partitioned:1; + u8 erase_opcode; + u8 command[4]; +}; + +static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) +{ + return container_of(mtd, struct m25p, mtd); +} + +/****************************************************************************/ + +/* + * Internal helper functions + */ + +/* + * Read the status register, returning its value in the location + * Return the status register value. + * Returns negative if error occurred. + */ +static int read_sr(struct m25p *flash) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; + + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | + IO_XFL_CTL1_FC_DATA(1); + io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDSR); + FLASH_COMMAND_EXEC(io); + + return io->status1 & 0xff; +} + +/* + * mem_flash_io_read_u32() + */ +static u32 mem_flash_io_read_u32(u32 addr) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | + IO_XFL_CTL1_FC_DATA(4) | IO_XFL_CTL1_FC_DUMMY(1) | + IO_XFL_CTL1_FC_ADDR; + io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_FAST_READ) | + IO_XFL_CTL2_FC_ADDR(addr); + FLASH_COMMAND_EXEC(io); + return io->status1; +} + +/* + * mem_flash_read_u8() + */ +static u8 mem_flash_read_u8(u32 addr) +{ + u32 tmp_addr = ALIGN_DOWN(addr, 4); + u32 tmp_data = mem_flash_io_read_u32(tmp_addr); + u8 *ptr = (u8 *)&tmp_data; + return ptr[addr & 0x3]; +} + +/* + * mem_flash_read() + * No need to lock as read is implemented with ireads (same as normal flash + * execution). + */ +static void mem_flash_read(u32 addr, void *dst, size_t length) +{ + /* + * Range check + */ + /* + * Fix source alignment. + */ + while (addr & 0x03) { + if (length == 0) { + return; + } + *((u8 *)dst) = mem_flash_read_u8(addr++); + dst++; + length--; + } + + while (length >= 4) { + u32 tmp_data = mem_flash_io_read_u32(addr); + addr += 4; + length -= 4; + + /* + * Send the data to the destination. + */ + memcpy((void *)dst, (void *)&tmp_data, 4); + dst += 4; + } + + while (length--) { + *((u8 *)dst) = mem_flash_read_u8(addr++); + dst++; + } +} + +/* + * mem_flash_wait_until_complete() + */ +static void mem_flash_wait_until_complete(void) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; + + do { + /* + * Put a delay here to deal with flash programming problem. + */ + u32 mptval = UBICOM32_IO_TIMER->mptval + TEN_MICRO_SECONDS; + while (UBICOM32_IO_TIMER->mptval < mptval) + ; + + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | + IO_XFL_CTL1_FC_DATA(1); + io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDSR); + FLASH_COMMAND_EXEC(io); + } while (io->status1 & SR_WIP); +} + +/* + * mem_flash_write_next() + */ +static size_t mem_flash_write_next(u32 addr, u8 *buf, size_t length) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; + u32 data_start = addr; + u32 data_end = addr + length; + size_t count; + u32 i, j; + + /* + * Top limit address. + */ + u32 block_start = ALIGN_DOWN(data_start, 4); + u32 block_end = block_start + EXTFLASH_WRITE_BLOCK_SIZE; + + union { + u8 byte[EXTFLASH_WRITE_BLOCK_SIZE]; + u32 word[EXTFLASH_WRITE_BLOCK_SIZE / 4]; + } write_buf; + + u32 *flash_addr = (u32 *)block_start; + + /* + * The write block must be limited by FLASH internal buffer. + */ + u32 block_end_align = ALIGN_DOWN(block_end, 256); + bool write_needed; + + block_end = (block_end_align > block_start) + ? block_end_align : block_end; + data_end = (data_end <= block_end) ? data_end : block_end; + block_end = ALIGN_UP(data_end, 4); + count = data_end - data_start; + + /* + * Transfer data to a buffer. + */ + for (i = 0; i < (block_end - block_start) / 4; i++) { + /* + * The FLASH read can hold D-cache for a long time. + * Use I/O operation to read FLASH to avoid starving other + * threads, especially HRT. (Do this for application only) + */ + write_buf.word[i] = mem_flash_io_read_u32( + (u32)(&flash_addr[i])); + } + + write_needed = false; + for (i = 0, j = (data_start - block_start); + i < (data_end - data_start); i++, j++) { + write_needed = write_needed || (write_buf.byte[j] != buf[i]); + write_buf.byte[j] &= buf[i]; + } + + + /* + * If the data in FLASH is identical to what to be written. Then skip + * it. + */ + if (write_needed) { + /* + * Write to flash. + */ + void *tmp __attribute__((unused)); + s32 extra_words; + + asm volatile( + " move.4 %0, %2 \n\t" + " bset "D(IO_INT_SET)"(%1), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)") \n\t" + " pipe_flush 0 \n\t" + " .rept "D(EXTFLASH_WRITE_FIFO_SIZE / 4)" \n\t" + " move.4 "D(IO_TX_FIFO)"(%1), (%0)4++ \n\t" + " .endr \n\t" + : "=&a" (tmp) + : "a" (io), "r" (&write_buf.word[0]) + : "memory", "cc" + ); + + /* Lock FLASH for write access. */ + io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; + + /* Command: WREN */ + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); + io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_WREN); + FLASH_COMMAND_EXEC(io); + + /* Command: BYTE PROGRAM */ + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | + IO_XFL_CTL1_FC_DATA(block_end - block_start) | + IO_XFL_CTL1_FC_ADDR; + io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_PP) | + IO_XFL_CTL2_FC_ADDR(block_start); + FLASH_COMMAND_KICK_OFF(io); + + extra_words = (s32)(block_end - block_start - + EXTFLASH_WRITE_FIFO_SIZE) / 4; + if (extra_words > 0) { + asm volatile( + " move.4 %0, %3 \n\t" + "1: cmpi "D(IO_FIFO_LEVEL)"(%1), #4 \n\t" + " jmpgt.s.t 1b \n\t" + " move.4 "D(IO_TX_FIFO)"(%1), (%0)4++ \n\t" + " add.4 %2, #-1, %2 \n\t" + " jmpgt.t 1b \n\t" + : "=&a" (tmp) + : "a" (io), "d" (extra_words), + "r" (&write_buf.word[EXTFLASH_WRITE_FIFO_SIZE / 4]) + : "memory", "cc" + ); + } + FLASH_COMMAND_WAIT_FOR_COMPLETION(io); + + mem_flash_wait_until_complete(); + + + /* Unlock FLASH for cache access. */ + io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; + } + + /* + * Complete. + */ + return count; +} + +/* + * mem_flash_write() + */ +static void mem_flash_write(u32 addr, const void *src, size_t length) +{ + /* + * Write data + */ + u8_t *ptr = (u8_t *)src; + while (length) { + size_t count = mem_flash_write_next(addr, ptr, length); + addr += count; + ptr += count; + length -= count; + } +} + +/* + * Service routine to read status register until ready, or timeout occurs. + * Returns non-zero if error. + */ +static int wait_till_ready(struct m25p *flash) +{ + int count; + int sr; + + /* one chip guarantees max 5 msec wait here after page writes, + * but potentially three seconds (!) after page erase. + */ + for (count = 0; count < MAX_READY_WAIT_COUNT; count++) { + u32 mptval; + sr = read_sr(flash); + if (sr < 0) + break; + else if (!(sr & SR_WIP)) + return 0; + + /* + * Put a 10us delay here to deal with flash programming problem. + */ + mptval = UBICOM32_IO_TIMER->mptval + TEN_MICRO_SECONDS; + while ((s32)(mptval - UBICOM32_IO_TIMER->mptval) > 0) { + WATCHDOG_RESET(); + } + /* REVISIT sometimes sleeping would be best */ + } + + return 1; +} + +/* + * mem_flash_erase_page() + */ +static void mem_flash_erase_page(u32 addr) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; + + /* Lock FLASH for write access. */ + io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; + + /* Command: WREN */ + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); + io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_WREN); + FLASH_COMMAND_EXEC(io); + + /* Command: ERASE */ + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD) | + IO_XFL_CTL1_FC_ADDR; + io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_SE) | + IO_XFL_CTL2_FC_ADDR(addr); + FLASH_COMMAND_EXEC(io); + + mem_flash_wait_until_complete(); + + /* Unlock FLASH for cache access. */ + io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; +} + +/* + * mem_flash_erase() + */ +static u32 mem_flash_erase(u32 addr, u32 length) +{ + /* + * Calculate the endaddress to be the first address of the page + * just beyond this erase section of pages. + */ + u32 endaddr = addr + length; + + /* + * Erase. + */ + while (addr < endaddr) { + u32 test_addr = addr; + mem_flash_erase_page(addr); + + /* + * Test how much was erased as actual flash page at this address + * may be smaller than the expected page size. + */ + while (test_addr < endaddr) { + /* + * The FLASH read can hold D-cache for a long time. Use + * I/O operation to read FLASH to avoid starving other + * threads, especially HRT. (Do this for application + * only) + */ + if (mem_flash_io_read_u32(test_addr) != 0xFFFFFFFF) { + break; + } + test_addr += 4; + } + if (test_addr == addr) { + printk("erase failed at address 0x%x, skipping", + test_addr); + test_addr += 4; + return 1; + } + addr = test_addr; + } + return 0; +} + + +/****************************************************************************/ + +/* + * MTD implementation + */ + +/* + * Erase an address range on the flash chip. The address range may extend + * one or more erase sectors. Return an error is there is a problem erasing. + */ +static int ubicom32_flash_driver_erase(struct mtd_info *mtd, + struct erase_info *instr) +{ + struct m25p *flash = mtd_to_m25p(mtd); + u32 addr, len; + + DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %lld\n", + dev_name(&flash->plt_dev->dev), __FUNCTION__, "at", + (u32)instr->addr, instr->len); + + /* sanity checks */ + if (instr->addr + instr->len > flash->mtd.size) + return -EINVAL; + if ((instr->addr % mtd->erasesize) != 0 + || (instr->len % mtd->erasesize) != 0) { + return -EINVAL; + } + + addr = instr->addr + UBICOM32_FLASH_BASE; + len = instr->len; + + mutex_lock(&flash->lock); + + /* REVISIT in some cases we could speed up erasing large regions + * by using OPCODE_SE instead of OPCODE_BE_4K + */ + + /* now erase those sectors */ + if (mem_flash_erase(addr, len)) { + instr->state = MTD_ERASE_FAILED; + mutex_unlock(&flash->lock); + return -EIO; + } + + mutex_unlock(&flash->lock); + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + return 0; +} + +/* + * Read an address range from the flash chip. The address range + * may be any size provided it is within the physical boundaries. + */ +static int ubicom32_flash_driver_read(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf) +{ + struct m25p *flash = mtd_to_m25p(mtd); + u32 base_addr = UBICOM32_FLASH_BASE + from; + + DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", + dev_name(&flash->plt_dev->dev), __FUNCTION__, "from", + (u32)from, len); + + /* sanity checks */ + if (!len) + return 0; + + if (from + len > flash->mtd.size) + return -EINVAL; + + /* Byte count starts at zero. */ + if (retlen) + *retlen = 0; + + mutex_lock(&flash->lock); + + /* Wait till previous write/erase is done. */ + if (wait_till_ready(flash)) { + /* REVISIT status return?? */ + mutex_unlock(&flash->lock); + return 1; + } + + mem_flash_read(base_addr, (void *)buf, len); + + if (retlen) + *retlen = len; + + mutex_unlock(&flash->lock); + + return 0; +} + +/* + * Write an address range to the flash chip. Data must be written in + * FLASH_PAGESIZE chunks. The address range may be any size provided + * it is within the physical boundaries. + */ +static int ubicom32_flash_driver_write(struct mtd_info *mtd, loff_t to, + size_t len, size_t *retlen, + const u_char *buf) +{ + struct m25p *flash = mtd_to_m25p(mtd); + u32 base_addr = UBICOM32_FLASH_BASE + to; + DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", + dev_name(&flash->plt_dev->dev), __FUNCTION__, "to", + (u32)to, len); + + if (retlen) + *retlen = 0; + + /* sanity checks */ + if (!len) + return 0; + + if (to + len > flash->mtd.size) + return -EINVAL; + + mutex_lock(&flash->lock); + + mem_flash_write(base_addr, (void *) buf, len); + + /* Wait until finished previous write command. */ + if (wait_till_ready(flash)) { + mutex_unlock(&flash->lock); + return 1; + } + + if (retlen) + *retlen = len; + + mutex_unlock(&flash->lock); + return 0; +} + + +/****************************************************************************/ + +/* + * SPI device driver setup and teardown + */ + +struct flash_info { + char *name; + + /* JEDEC id zero means "no ID" (most older chips); otherwise it has + * a high byte of zero plus three data bytes: the manufacturer id, + * then a two byte device id. + */ + u32 jedec_id; + + /* The size listed here is what works with OPCODE_SE, which isn't + * necessarily called a "sector" by the vendor. + */ + unsigned sector_size; + u16 n_sectors; + + u16 flags; +#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ +}; + + +/* NOTE: double check command sets and memory organization when you add + * more flash chips. This current list focusses on newer chips, which + * have been converging on command sets which including JEDEC ID. + */ +static struct flash_info __devinitdata m25p_data[] = { + + /* Atmel -- some are (confusingly) marketed as "DataFlash" */ + { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, }, + { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, + + { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, + + { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, + { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, + { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, }, + { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, }, + + /* Spansion -- single (large) sector size only, at least + * for the chips listed here (without boot sectors). + */ + { "s25sl004a", 0x010212, 64 * 1024, 8, }, + { "s25sl008a", 0x010213, 64 * 1024, 16, }, + { "s25sl016a", 0x010214, 64 * 1024, 32, }, + { "s25sl032a", 0x010215, 64 * 1024, 64, }, + { "s25sl064a", 0x010216, 64 * 1024, 128, }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4K */ + { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, }, + { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, }, + { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, }, + { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, }, + + /* ST Microelectronics -- newer production may have feature updates */ + { "m25p05", 0x202010, 32 * 1024, 2, }, + { "m25p10", 0x202011, 32 * 1024, 4, }, + { "m25p20", 0x202012, 64 * 1024, 4, }, + { "m25p40", 0x202013, 64 * 1024, 8, }, + { "m25p80", 0, 64 * 1024, 16, }, + { "m25p16", 0x202015, 64 * 1024, 32, }, + { "m25p32", 0x202016, 64 * 1024, 64, }, + { "m25p64", 0x202017, 64 * 1024, 128, }, + { "m25p128", 0x202018, 256 * 1024, 64, }, + + { "m45pe80", 0x204014, 64 * 1024, 16, }, + { "m45pe16", 0x204015, 64 * 1024, 32, }, + + { "m25pe80", 0x208014, 64 * 1024, 16, }, + { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, }, + + /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ + { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, }, + { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, }, + { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, }, + { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, }, + { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, }, + { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, }, + { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, }, + + /* Macronix -- mx25lxxx */ + { "mx25l32", 0xc22016, 64 * 1024, 64, }, + { "mx25l64", 0xc22017, 64 * 1024, 128, }, + { "mx25l128", 0xc22018, 64 * 1024, 256, }, + +}; + +struct flash_info *__devinit jedec_probe(struct platform_device *spi) +{ + int tmp; + u32 jedec; + struct flash_info *info; + struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; + + /* + * Setup and run RDID command on the flash. + */ + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | + IO_XFL_CTL1_FC_DATA(3); + io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDID); + FLASH_COMMAND_EXEC(io); + + jedec = io->status1 & 0x00ffffff; + + for (tmp = 0, info = m25p_data; + tmp < ARRAY_SIZE(m25p_data); + tmp++, info++) { + if (info->jedec_id == jedec) + return info; + } + dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); + return NULL; +} + + +/* + * board specific setup should have ensured the SPI clock used here + * matches what the READ command supports, at least until this driver + * understands FAST_READ (for clocks over 25 MHz). + */ +static int __devinit ubicom32_flash_probe(struct platform_device *spi) +{ + struct flash_platform_data *data; + struct m25p *flash; + struct flash_info *info; + unsigned i; + + /* Platform data helps sort out which chip type we have, as + * well as how this board partitions it. If we don't have + * a chip ID, try the JEDEC id commands; they'll work for most + * newer chips, even if we don't recognize the particular chip. + */ + data = spi->dev.platform_data; + if (data && data->type) { + for (i = 0, info = m25p_data; + i < ARRAY_SIZE(m25p_data); + i++, info++) { + if (strcmp(data->type, info->name) == 0) + break; + } + + /* unrecognized chip? */ + if (i == ARRAY_SIZE(m25p_data)) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n", + dev_name(&spi->dev), data->type); + info = NULL; + + /* recognized; is that chip really what's there? */ + } else if (info->jedec_id) { + struct flash_info *chip = jedec_probe(spi); + + if (!chip || chip != info) { + dev_warn(&spi->dev, "found %s, expected %s\n", + chip ? chip->name : "UNKNOWN", + info->name); + info = NULL; + } + } + } else + info = jedec_probe(spi); + + if (!info) + return -ENODEV; + + flash = kzalloc(sizeof *flash, GFP_KERNEL); + if (!flash) + return -ENOMEM; + + flash->plt_dev = spi; + mutex_init(&flash->lock); + dev_set_drvdata(&spi->dev, flash); + + if (data && data->name) + flash->mtd.name = data->name; + else + flash->mtd.name = dev_name(&spi->dev); + + flash->mtd.type = MTD_NORFLASH; + flash->mtd.writesize = 1; + flash->mtd.flags = MTD_CAP_NORFLASH; + flash->mtd.size = info->sector_size * info->n_sectors; + flash->mtd.erase = ubicom32_flash_driver_erase; + flash->mtd.read = ubicom32_flash_driver_read; + flash->mtd.write = ubicom32_flash_driver_write; + + /* prefer "small sector" erase if possible */ + /* + * The Ubicom erase code does not use the opcode for smaller sectors, + * so disable that functionality and keep erasesize == sector_size + * so that the test in ubicom32_flash_driver_erase works properly. + * + * This was: `if (info->flags & SECT_4K) {' instead of `if (0) {' + */ + if (0) { + flash->erase_opcode = OPCODE_BE_4K; + flash->mtd.erasesize = 4096; + } else { + flash->erase_opcode = OPCODE_SE; + flash->mtd.erasesize = info->sector_size; + } + + dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name, + flash->mtd.size / 1024); + + DEBUG(MTD_DEBUG_LEVEL2, + "mtd .name = %s, .size = 0x%.8llx (%lluMiB) " + ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", + flash->mtd.name, + flash->mtd.size, flash->mtd.size / (1024*1024), + flash->mtd.erasesize, flash->mtd.erasesize / 1024, + flash->mtd.numeraseregions); + + if (flash->mtd.numeraseregions) + for (i = 0; i < flash->mtd.numeraseregions; i++) + DEBUG(MTD_DEBUG_LEVEL2, + "mtd.eraseregions[%d] = { .offset = 0x%.8llx, " + ".erasesize = 0x%.8x (%uKiB), " + ".numblocks = %d }\n", + i, flash->mtd.eraseregions[i].offset, + flash->mtd.eraseregions[i].erasesize, + flash->mtd.eraseregions[i].erasesize / 1024, + flash->mtd.eraseregions[i].numblocks); + + + /* partitions should match sector boundaries; and it may be good to + * use readonly partitions for writeprotected sectors (BP2..BP0). + */ + if (mtd_has_partitions()) { + struct mtd_partition *parts = NULL; + int nr_parts = 0; + +#ifdef CONFIG_MTD_CMDLINE_PARTS + static const char *part_probes[] = { "cmdlinepart", NULL, }; + + nr_parts = parse_mtd_partitions(&flash->mtd, + part_probes, &parts, 0); +#endif + + if (nr_parts <= 0 && data && data->parts) { + parts = data->parts; + nr_parts = data->nr_parts; + if (nr_parts >= 2) { + /* + * Set last partition size to be 1M. + */ + parts[1].size = flash->mtd.size - + parts[0].size - JFFS2_FILESYSTEM_SIZE; + parts[2].size = JFFS2_FILESYSTEM_SIZE; + } + } + + if (nr_parts > 0) { + for (i = 0; i < nr_parts; i++) { + DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " + "{.name = %s, .offset = 0x%.8llx, " + ".size = 0x%.8llx (%lluKiB) }\n", + i, parts[i].name, + parts[i].offset, + parts[i].size, + parts[i].size / 1024); + } + flash->partitioned = 1; + return add_mtd_partitions(&flash->mtd, parts, nr_parts); + } + } else if (data->nr_parts) + dev_warn(&spi->dev, "ignoring %d default partitions on %s\n", + data->nr_parts, data->name); + + return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0; +} + + +static int __devexit ubicom32_flash_remove(struct spi_device *spi) +{ + struct m25p *flash = dev_get_drvdata(&spi->dev); + int status; + + /* Clean up MTD stuff. */ + if (mtd_has_partitions() && flash->partitioned) + status = del_mtd_partitions(&flash->mtd); + else + status = del_mtd_device(&flash->mtd); + if (status == 0) + kfree(flash); + return 0; +} + +static struct platform_driver ubicom32_flash_driver = { + .driver = { + .name = "ubicom32flashdriver", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + }, + .probe = ubicom32_flash_probe, + .remove = NULL, +}; + +static int ubicom32_flash_driver_init(void) +{ + return platform_driver_register(&ubicom32_flash_driver); +} + + +static void ubicom32_flash_driver_exit(void) +{ + platform_driver_unregister(&ubicom32_flash_driver); +} + + +module_init(ubicom32_flash_driver_init); +module_exit(ubicom32_flash_driver_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mike Lavender"); +MODULE_DESCRIPTION("Ubicom32 MTD SPI driver for ST M25Pxx flash chips"); diff --git a/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-nand-spi-er.c b/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-nand-spi-er.c new file mode 100644 index 000000000..897bed787 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-nand-spi-er.c @@ -0,0 +1,1188 @@ +/* + * Micron SPI-ER NAND Flash Memory + * This code uses the built in Ubicom flash controller + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "ubi32-nand-spi-er" +#define UBI32_NAND_SPI_ER_BLOCK_FROM_ROW(row) (row >> 6) + +#define UBI32_NAND_SPI_ER_STATUS_P_FAIL (1 << 3) +#define UBI32_NAND_SPI_ER_STATUS_E_FAIL (1 << 2) +#define UBI32_NAND_SPI_ER_STATUS_OIP (1 << 0) + +#define UBI32_NAND_SPI_ER_LAST_ROW_INVALID 0xFFFFFFFF +#define UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET 0x08 + +struct ubi32_nand_spi_er_device { + const char *name; + + uint16_t id; + + unsigned int blocks; + unsigned int pages_per_block; + unsigned int page_size; + unsigned int write_size; + unsigned int erase_size; +}; + +struct ubi32_nand_spi_er { + char name[24]; + + const struct ubi32_nand_spi_er_device *device; + + struct mutex lock; + struct platform_device *pdev; + + struct mtd_info mtd; + + unsigned int last_row; /* the last row we fetched */ + + /* + * Bad block table (MUST be last in strcuture) + */ + unsigned long nbb; + unsigned long bbt[0]; +}; + +/* + * Chip supports a write_size of 512, but we cannot do partial + * page with command 0x84. + * + * We need to use command 0x84 because we cannot fill the FIFO fast + * enough to transfer the whole 512 bytes at a time. (maybe through + * OCM?) + */ +const struct ubi32_nand_spi_er_device ubi32_nand_spi_er_devices[] = { + { + name: "MT29F1G01ZDC", + id: 0x2C12, + blocks: 1024, + pages_per_block: 64, + page_size: 2048, + write_size: 2048, + erase_size: 64 * 2048, + }, + { + name: "MT29F1G01ZDC", + id: 0x2C13, + blocks: 1024, + pages_per_block: 64, + page_size: 2048, + write_size: 2048, + erase_size: 64 * 2048, + }, +}; + +static int read_only = 0; +module_param(read_only, int, 0); +MODULE_PARM_DESC(read_only, "Leave device locked"); + +/* + * Ubicom32 FLASH Command Set + */ +#define FLASH_PORT RA + +#define FLASH_FC_INST_CMD 0x00 /* for SPI command only transaction */ +#define FLASH_FC_INST_WR 0x01 /* for SPI write transaction */ +#define FLASH_FC_INST_RD 0x02 /* for SPI read transaction */ + +#define FLASH_COMMAND_KICK_OFF(io) \ + asm volatile( \ + " bset "D(IO_INT_CLR)"(%0), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" \ + " jmpt.t .+4 \n\t" \ + " bset "D(IO_INT_SET)"(%0), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" \ + : \ + : "a" (io) \ + : "cc" \ + ); + +#define FLASH_COMMAND_WAIT_FOR_COMPLETION(io) \ + asm volatile( \ + " btst "D(IO_INT_STATUS)"(%0), #%%bit("D(IO_XFL_INT_DONE)") \n\t" \ + " jmpeq.f .-4 \n\t" \ + : \ + : "a" (io) \ + : "cc" \ + ); + +#define FLASH_COMMAND_EXEC(io) \ + FLASH_COMMAND_KICK_OFF(io) \ + FLASH_COMMAND_WAIT_FOR_COMPLETION(io) + +/* + * ubi32_nand_spi_er_get_feature + * Get Feature register + */ +static uint8_t ubi32_nand_spi_er_get_feature(uint32_t reg) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + + /* + * Note that this will produce the sequence: + * SI [0F][REG][00][00] + * SO ---------[SR][SR][SR] + * Since the flash controller can only output 24 bits of address, this is + * ok for this command since the data will just repeat as long as the CS + * is asserted and the clock is running. + */ + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(1) | + IO_XFL_CTL1_FC_ADDR; + io->ctl2 = IO_XFL_CTL2_FC_CMD(0x0F) | IO_XFL_CTL2_FC_ADDR(reg << 16); + FLASH_COMMAND_EXEC(io); + + return io->status1 & 0xFF; +} + +/* + * ubi32_nand_spi_er_write_buf + * writes a buffer to the bus + * + * Writes 511 + 1 bytes to the bus, we have to stuff one data byte into the address. + */ +static void ubi32_nand_spi_er_write_buf(const uint8_t *buf, uint32_t col) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + uint32_t tmp; + + asm volatile ( + " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)") \n\t" + " pipe_flush 0 \n\t" + : + : [port] "a" (FLASH_PORT) + : "cc" + ); + + /* + * Write the data into the cache + */ + io->ctl1 &= ~IO_XFL_CTL1_MASK; +#ifdef SUPPORT_512_FIFO + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(511) | +#endif + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(31) | + IO_XFL_CTL1_FC_ADDR; + + /* + * Construct the address with the first byte of data + */ + tmp = (col << 8) | *buf++; + io->ctl2 = IO_XFL_CTL2_FC_CMD(0x84) | IO_XFL_CTL2_FC_ADDR(tmp); + + asm volatile ( + + /* + * Move 32 bytes + * + * The first word needs to be [11][22][33][33] to work around a flash + * controller bug. + */ + " move.2 %[tmp], (%[data])2++ \n\t" + " shmrg.1 %[tmp], (%[data]), %[tmp] \n\t" + " shmrg.1 %[tmp], (%[data])1++, %[tmp] \n\t" + " move.4 "D(IO_TX_FIFO)"(%[port]), %[tmp] \n\t" + + /* + * We're aligned again! + */ + " .rept 7 \n\t" + " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" + " .endr \n\t" + + /* + * Kick off the flash command + */ + " bset "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" + " jmpt.t .+4 \n\t" + " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" + +#ifdef SUPPORT_512_FIFO + /* + * Fill the remaining 120 words as space becomes available + */ + "1: \n\t" + " cmpi "D(IO_FIFO_LEVEL)"(%[port]), #4 \n\t" + " jmpgt.s.t 1b \n\t" + " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" + " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" + " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" + " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" + " add.4 %[cnt], #-4, %[cnt] \n\t" + " jmpgt.t 1b \n\t" +#endif + /* + * Wait for the transaction to finish + */ + " btst "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)") \n\t" + " jmpeq.f .-4 \n\t" + + : [tmp] "=&d" (tmp), + [data] "+&a" (buf) + : [column] "d" (col), + [port] "a" (FLASH_PORT), + [cnt] "d" (120) // see above comment + : "cc" + ); +} + +/* + * ubi32_nand_spi_er_send_rd_addr + * perform FC_RD: CMD + address + */ +static void ubi32_nand_spi_er_send_rd_addr(uint8_t command, uint32_t address) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(4) | + IO_XFL_CTL1_FC_ADDR; + io->ctl2 = IO_XFL_CTL2_FC_CMD(command) | IO_XFL_CTL2_FC_ADDR(address); + FLASH_COMMAND_EXEC(io); +} + +/* + * ubi32_nand_spi_er_send_cmd_addr + * perform FC_(xxx): CMD + address + */ +static void ubi32_nand_spi_er_send_cmd_addr(uint8_t command, uint32_t address) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD) | IO_XFL_CTL1_FC_ADDR; + io->ctl2 = IO_XFL_CTL2_FC_CMD(command) | IO_XFL_CTL2_FC_ADDR(address); + FLASH_COMMAND_EXEC(io); +} + +/* + * ubi32_nand_spi_er_write_disable + * clear the write enable bit + */ +static void ubi32_nand_spi_er_write_disable(void) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); + io->ctl2 = IO_XFL_CTL2_FC_CMD(0x04); + FLASH_COMMAND_EXEC(io); +} + +/* + * ubi32_nand_spi_er_write_enable + * set the write enable bit + */ +static void ubi32_nand_spi_er_write_enable(void) +{ + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); + io->ctl2 = IO_XFL_CTL2_FC_CMD(0x06); + FLASH_COMMAND_EXEC(io); +} + +/* + * ubi32_nand_spi_er_busywait + * Wait until the chip is not busy + */ +static uint8_t ubi32_nand_spi_er_busywait(void) +{ + int i; + uint8_t data; + + /* + * tRD is 100us, so don't delay too long, however, tERS is + * 10ms so you'd better loop enough. + */ + for (i = 0; i < 200; i++) { + data = ubi32_nand_spi_er_get_feature(0xC0); + if (!(data & UBI32_NAND_SPI_ER_STATUS_OIP)) { + break; + } + + udelay(50); + } + + return data; +} + +/* + * ubi32_nand_spi_er_erase + * Erase a block, parameters must be block aligned + */ +static int ubi32_nand_spi_er_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct ubi32_nand_spi_er *chip = mtd->priv; + int res; + + DEBUG(MTD_DEBUG_LEVEL3, "%s: erase addr:%x len:%x\n", chip->name, instr->addr, instr->len); + + if ((instr->addr + instr->len) > mtd->size) { + return -EINVAL; + } + + if (instr->addr & (chip->device->erase_size - 1)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: erase address is not aligned %x\n", chip->name, instr->addr); + return -EINVAL; + } + + if (instr->len & (chip->device->erase_size - 1)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: erase len is not aligned %x\n", chip->name, instr->len); + return -EINVAL; + } + + mutex_lock(&chip->lock); + chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; + + while (instr->len) { + uint32_t block = instr->addr >> 17; + uint32_t row = block << 6; + uint8_t stat; + DEBUG(MTD_DEBUG_LEVEL3, "%s: block erase row:%x block:%x addr:%x rem:%x\n", chip->name, row, block, instr->addr, instr->len); + + /* + * Test for bad block + */ + if (test_bit(block, chip->bbt)) { + instr->fail_addr = block << 17; + instr->state = MTD_ERASE_FAILED; + res = -EBADMSG; + goto done; + } + + ubi32_nand_spi_er_write_enable(); + + /* + * Block erase + */ + ubi32_nand_spi_er_send_cmd_addr(0xD8, row); + + /* + * Wait + */ + stat = ubi32_nand_spi_er_busywait(); + if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { + instr->fail_addr = block << 17; + instr->state = MTD_ERASE_FAILED; + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); + + /* + * Chip is stuck? + */ + res = -EIO; + goto done; + } + + /* + * Check the status register + */ + if (stat & UBI32_NAND_SPI_ER_STATUS_E_FAIL) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: E_FAIL signalled (%02x)\n", chip->name, stat); + instr->fail_addr = block << 17; + instr->state = MTD_ERASE_FAILED; + goto done; + } + + /* + * Next + */ + block++; + instr->len -= chip->device->erase_size; + instr->addr += chip->device->erase_size; + } + + instr->state = MTD_ERASE_DONE; + + mutex_unlock(&chip->lock); + return 0; + +done: + ubi32_nand_spi_er_write_disable(); + + mutex_unlock(&chip->lock); + + mtd_erase_callback(instr); + return 0; +} + +/* + * ubi32_nand_spi_er_read + * + * return -EUCLEAN: ecc error recovered + * return -EBADMSG: ecc error not recovered +*/ +static int ubi32_nand_spi_er_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct ubi32_nand_spi_er *chip = mtd->priv; + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + + uint32_t row; + uint32_t column; + int retval = 0; + uint32_t *pbuf = (uint32_t *)buf; + + *retlen = 0; + DEBUG(MTD_DEBUG_LEVEL2, "%s: read block from %llx len %d into %p\n", chip->name, from, len, buf); + + /* + * buf should be aligned + */ + if ((uint32_t)buf & 0x03) { + return -EINVAL; + } + + /* + * Zero length reads, nothing to do + */ + if (len == 0) { + return 0; + } + + /* + * Reject reads which go over the end of the flash + */ + if ((from + len) > mtd->size) { + return -EINVAL; + } + + /* + * Get the row and column address to start at + */ + row = from >> 11; + column = from & 0x7FF; + DEBUG(MTD_DEBUG_LEVEL3, "%s: row=%x %d column=%x %d last_row=%x %d\n", chip->name, row, row, column, column, chip->last_row, chip->last_row); + + /* + * Read the data from the chip + */ + mutex_lock(&chip->lock); + while (len) { + uint8_t stat; + size_t toread; + int i; + int tmp; + + /* + * Figure out how much to read + * + * If we are reading from the middle of a page then the most we + * can read is to the end of the page + */ + toread = len; + if (toread > (chip->device->page_size - column)) { + toread = chip->device->page_size - column; + } + + DEBUG(MTD_DEBUG_LEVEL3, "%s: buf=%p toread=%x row=%x column=%x last_row=%x\n", chip->name, pbuf, toread, row, column, chip->last_row); + + if (chip->last_row != row) { + /* + * Check if the block is bad + */ + if (test_bit(UBI32_NAND_SPI_ER_BLOCK_FROM_ROW(row), chip->bbt)) { + mutex_unlock(&chip->lock); + return -EBADMSG; + } + + /* + * Load the appropriate page + */ + ubi32_nand_spi_er_send_cmd_addr(0x13, row); + + /* + * Wait + */ + stat = ubi32_nand_spi_er_busywait(); + if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); + + /* + * Chip is stuck? + */ + mutex_unlock(&chip->lock); + return -EIO; + } + + /* + * Check the ECC bits + */ + stat >>= 4; + if (stat == 1) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: ECC recovered, row=%x\n", chip->name, row); + retval = -EUCLEAN; + } + if (stat == 2) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: failed ECC, row=%x\n", chip->name, row); + chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; + mutex_unlock(&chip->lock); + return -EBADMSG; + } + + } + + chip->last_row = row; + + /* + * Read out the data: + * We can always read a little too much since there is the + * OOB after byte addr 2047. The most we'll overread is 3 bytes. + */ + if (((uint32_t)pbuf & 0x03) == 0) { + /* + * Aligned read + */ + tmp = toread & (~0x03); + for (i = 0; i < tmp; i += 4) { + ubi32_nand_spi_er_send_rd_addr(0x03, column << 8); + *pbuf++ = io->status1; + column += 4; + } + } else { + /* + * Unaligned read + */ + tmp = toread & (~0x03); + for (i = 0; i < tmp; i += 4) { + ubi32_nand_spi_er_send_rd_addr(0x03, column << 8); + memcpy(pbuf, &io->status1, 4); + column += 4; + } + } + + /* + * Fill in any single bytes + */ + tmp = toread & 0x03; + if (tmp) { + uint8_t *bbuf = pbuf; + uint32_t val; + ubi32_nand_spi_er_send_rd_addr(0x03, column << 8); + val = io->status1; + for (i = 0; i < tmp; i++) { + *bbuf++ = val >> 24; + val <<= 8; + } + } + + len -= toread; + *retlen += toread; + + /* + * For the next page, increment the row and always start at column 0 + */ + column = 0; + row++; + } + + mutex_unlock(&chip->lock); + return retval; +} + +/* + * ubi32_nand_spi_er_write + */ +#define WRITE_NOT_ALIGNED(x) ((x & (device->write_size - 1)) != 0) +static int ubi32_nand_spi_er_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct ubi32_nand_spi_er *chip = mtd->priv; + const struct ubi32_nand_spi_er_device *device = chip->device; + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + uint32_t row; + uint32_t col; + int res = 0; + size_t towrite; + + DEBUG(MTD_DEBUG_LEVEL2, "%s: write block to %llx len %d from %p\n", chip->name, to, len, buf); + + *retlen = 0; + + /* + * nothing to write + */ + if (!len) { + return 0; + } + + /* + * Reject writes which go over the end of the flash + */ + if ((to + len) > mtd->size) { + return -EINVAL; + } + + /* + * buf should be aligned to 16 bits + */ + if ((uint32_t)buf & 0x01) { + return -EINVAL; + } + + /* + * Check to see if everything is page aligned + */ + if (WRITE_NOT_ALIGNED(to) || WRITE_NOT_ALIGNED(len)) { + printk(KERN_NOTICE "ubi32_nand_spi_er_write: Attempt to write non page aligned data\n"); + return -EINVAL; + } + + mutex_lock(&chip->lock); + + io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; + + chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; + + /* + * If the first write is a partial write then write at most the number of + * bytes to get us page aligned and then the remainder will be + * page aligned. The last bit may be a partial page as well. + */ + col = to & (device->page_size - 1); + towrite = device->page_size - col; + if (towrite > len) { + towrite = len; + } + + /* + * Write the data + */ + row = to >> 11; + while (len) { + uint8_t stat; + uint32_t my_towrite; + + DEBUG(MTD_DEBUG_LEVEL3, "%s: write %p to row:%x col:%x len:%x rem:%x\n", chip->name, buf, row, col, towrite, len); + + ubi32_nand_spi_er_write_enable(); + + /* + * Move the data into the cache + */ + my_towrite = towrite; + while (my_towrite) { + uint32_t len = my_towrite; + if (len > 32) { + len = 32; + } + + ubi32_nand_spi_er_write_buf(buf, col); + buf += len; + col += len; + my_towrite -= len; + } + + /* + * Program execute + */ + ubi32_nand_spi_er_send_cmd_addr(0x10, row); + + /* + * Wait + */ + stat = ubi32_nand_spi_er_busywait(); + if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); + + /* + * Chip is stuck? + */ + res = -EIO; + goto done; + } + + if (stat & (1 << 3)) { + res = -EBADMSG; + goto done; + } + + row++; + len -= towrite; + *retlen += towrite; + + /* + * At this point, we are always page aligned so start at column 0. + * Note we may not have a full page to write at the end, hence the + * check if towrite > len. + */ + col = 0; + towrite = device->page_size; + if (towrite > len) { + towrite = len; + } + } + + io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; + + mutex_unlock(&chip->lock); + return res; + +done: + ubi32_nand_spi_er_write_disable(); + + io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; + + mutex_unlock(&chip->lock); + + return res; +} + +/* + * ubi32_nand_spi_er_isbad + */ +static int ubi32_nand_spi_er_isbad(struct mtd_info *mtd, loff_t ofs) +{ + struct ubi32_nand_spi_er *chip = mtd->priv; + uint32_t block; + + if (ofs & (chip->device->erase_size - 1)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs); + return -EINVAL; + } + + block = ofs >> 17; + + return test_bit(block, chip->bbt); +} + +/* + * ubi32_nand_spi_er_markbad + */ +static int ubi32_nand_spi_er_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct ubi32_nand_spi_er *chip = mtd->priv; + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + uint32_t block; + uint32_t row; + int res = 0; + uint8_t stat; + + if (ofs & (chip->device->erase_size - 1)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs); + return -EINVAL; + } + + block = ofs >> 17; + + /* + * If it's already marked bad, no need to mark it + */ + if (test_bit(block, chip->bbt)) { + return 0; + } + + /* + * Mark it in our cache + */ + __set_bit(block, chip->bbt); + + /* + * Write the user bad block mark. If it fails, then we really + * can't do anything about it. + */ + mutex_lock(&chip->lock); + chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; + + ubi32_nand_spi_er_write_enable(); + + /* + * Write the mark + */ + io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(6); + io->ctl2 = IO_XFL_CTL2_FC_CMD(0x84); + + asm volatile ( + " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)") \n\t" + " pipe_flush 0 \n\t" + + /* + * Move the data into the FIFO + */ + " move.4 "D(IO_TX_FIFO)"(%[port]), %[word1] \n\t" + " move.4 "D(IO_TX_FIFO)"(%[port]), %[word2] \n\t" + + /* + * Kick off the flash command + */ + " bset "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" + " jmpt.t .+4 \n\t" + " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" + + /* + * Wait for the transaction to finish + */ + " btst "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)") \n\t" + " jmpeq.f .-4 \n\t" + + : + : [word1] "d" (0x0800dead | (UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET << 16)), + [word2] "d" (0xbeef0000), + [port] "a" (FLASH_PORT) + : "cc" + ); + + io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; + + /* + * Program execute + */ + row = block << 6; + ubi32_nand_spi_er_send_cmd_addr(0x10, row); + + /* + * Wait + */ + stat = ubi32_nand_spi_er_busywait(); + if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); + + /* + * Chip is stuck? + */ + res = -EIO; + goto done; + } + + if (stat & (1 << 3)) { + res = -EBADMSG; + } + +done: + ubi32_nand_spi_er_write_disable(); + + mutex_unlock(&chip->lock); + + return res; +} + +/* + * ubi32_nand_spi_er_read_bbt + */ +static int ubi32_nand_spi_er_read_bbt(struct ubi32_nand_spi_er *chip) +{ + int j; + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + + for (j = 0; j < chip->device->blocks; j++) { + unsigned short row = j << 6; + uint8_t stat; + + /* + * Read Page + */ + ubi32_nand_spi_er_send_cmd_addr(0x13, row); + + /* + * Wait + */ + stat = ubi32_nand_spi_er_busywait(); + if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); + + /* + * Chip is stuck? + */ + return -EIO; + } + + /* + * Check factory bad block mark + */ + ubi32_nand_spi_er_send_rd_addr(0x03, 0x080000); + + if ((io->status1 >> 24) != 0xFF) { + chip->nbb++; + __set_bit(j, chip->bbt); + continue; + } + + ubi32_nand_spi_er_send_rd_addr(0x03, 0x080000 | (UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET << 8)); + if (io->status1 == 0xdeadbeef) { + chip->nbb++; + __set_bit(j, chip->bbt); + } + } + +#if defined(CONFIG_MTD_DEBUG) && (MTD_DEBUG_LEVEL3 <= CONFIG_MTD_DEBUG_VERBOSE) + printk("%s: Bad Block Table:", chip->name); + for (j = 0; j < chip->device->blocks; j++) { + if ((j % 64) == 0) { + printk("\n%s: block %03x: ", chip->name, j); + } + printk("%c", test_bit(j, chip->bbt) ? 'X' : '.'); + } + printk("\n%s: Bad Block Numbers: ", chip->name); + for (j = 0; j < chip->device->blocks; j++) { + if (test_bit(j, chip->bbt)) { + printk("%x ", j); + } + } + printk("\n"); +#endif + + return 0; +} + +#ifndef MODULE +/* + * Called at boot time: + * + * ubi32_nand_spi_er=read_only + * if read_only specified then do not unlock device + */ +static int __init ubi32_nand_spi_er_setup(char *str) +{ + if (str && (strncasecmp(str, "read_only", 9) == 0)) { + read_only = 1; + } + return 0; +} + +__setup("ubi32_nand_spi_er=", ubi32_nand_spi_er_setup); +#endif + +/* + * ubi32_nand_spi_er_probe + * Detect and initialize ubi32_nand_spi_er device. + */ +static int __devinit ubi32_nand_spi_er_probe(struct platform_device *pdev) +{ + uint32_t i; + uint32_t id; + int res; + size_t bbt_bytes; + struct ubi32_nand_spi_er *chip; + const struct ubi32_nand_spi_er_device *device; + struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; + + /* + * Reset + */ + for (i = 0; i < 2; i++) { + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); + io->ctl2 = IO_XFL_CTL2_FC_CMD(0xFF); + FLASH_COMMAND_EXEC(io); + udelay(250); + } + udelay(1000); + + /* + * Read out ID + */ + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(2) | + IO_XFL_CTL1_FC_ADDR; + io->ctl2 = IO_XFL_CTL2_FC_CMD(0x9F); + FLASH_COMMAND_EXEC(io); + + id = io->status1 >> 16; + device = ubi32_nand_spi_er_devices; + for (i = 0; i < ARRAY_SIZE(ubi32_nand_spi_er_devices); i++) { + if (device->id == id) { + break; + } + device++; + } + if (i == ARRAY_SIZE(ubi32_nand_spi_er_devices)) { + return -ENODEV; + } + + /* + * Initialize our chip structure + */ + bbt_bytes = DIV_ROUND_UP(device->blocks, BITS_PER_BYTE); + chip = kzalloc(sizeof(struct ubi32_nand_spi_er) + bbt_bytes, GFP_KERNEL); + if (!chip) { + return -ENOMEM; + } + snprintf(chip->name, sizeof(chip->name), "%s", device->name); + + chip->device = device; + chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; + + mutex_init(&chip->lock); + + chip->mtd.type = MTD_NANDFLASH; + chip->mtd.flags = MTD_WRITEABLE; + + /* + * #blocks * block size * n blocks + */ + chip->mtd.size = device->blocks * device->pages_per_block * device->page_size; + chip->mtd.erasesize = device->erase_size; + + /* + * 1 page, optionally we can support partial write (512) + */ + chip->mtd.writesize = device->write_size; + chip->mtd.name = device->name; + chip->mtd.erase = ubi32_nand_spi_er_erase; + chip->mtd.read = ubi32_nand_spi_er_read; + chip->mtd.write = ubi32_nand_spi_er_write; + chip->mtd.block_isbad = ubi32_nand_spi_er_isbad; + chip->mtd.block_markbad = ubi32_nand_spi_er_markbad; + chip->mtd.priv = chip; + + /* + * Cache the bad block table + */ + res = ubi32_nand_spi_er_read_bbt(chip); + if (res) { + kfree(chip); + return res; + } + + /* + * Un/lock the chip + */ + io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; + io->ctl1 &= ~IO_XFL_CTL1_MASK; + io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(2); + io->ctl2 = IO_XFL_CTL2_FC_CMD(0x1F); + + if (read_only) { + i = 0xa0380000; + } else { + i = 0xa0000000; + } + asm volatile ( + " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)") \n\t" + " pipe_flush 0 \n\t" + + /* + * Move the data into the FIFO + */ + " move.4 "D(IO_TX_FIFO)"(%[port]), %[word1] \n\t" + + /* + * Kick off the flash command + */ + " bset "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" + " jmpt.t .+4 \n\t" + " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" + + /* + * Wait for the transaction to finish + */ + " btst "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)") \n\t" + " jmpeq.f .-4 \n\t" + + : + : [word1] "d" (i), + [port] "a" (FLASH_PORT) + : "cc" + ); + io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; + + dev_set_drvdata(&pdev->dev, chip); + + printk(KERN_INFO "%s: added device size: %u KBytes %lu bad blocks %s\n", chip->mtd.name, DIV_ROUND_UP(chip->mtd.size, 1024), chip->nbb, read_only ? "[read only]" : ""); + return add_mtd_device(&chip->mtd); +} + +/* + * ubi32_nand_spi_er_remove + */ +static int __devexit ubi32_nand_spi_er_remove(struct platform_device *pdev) +{ + struct ubi32_nand_spi_er *chip = dev_get_drvdata(&pdev->dev); + int status; + + DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", chip->name); + + status = del_mtd_device(&chip->mtd); + if (status == 0) { + kfree(chip); + } + + dev_set_drvdata(&pdev->dev, NULL); + return status; +} + +static struct platform_device *ubi32_nand_spi_er_device; + +static struct platform_driver ubi32_nand_spi_er_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + + .probe = ubi32_nand_spi_er_probe, + .remove = ubi32_nand_spi_er_remove, +}; + +/* + * ubi32_nand_spi_er_init + */ +static int __init ubi32_nand_spi_er_init(void) +{ + int ret; + + ret = platform_driver_register(&ubi32_nand_spi_er_driver); + + if (ret) { + return ret; + } + + ubi32_nand_spi_er_device = platform_device_alloc(DRIVER_NAME, 0); + if (!ubi32_nand_spi_er_device) { + return -ENOMEM; + } + + ret = platform_device_add(ubi32_nand_spi_er_device); + if (ret) { + platform_device_put(ubi32_nand_spi_er_device); + platform_driver_unregister(&ubi32_nand_spi_er_driver); + } + + return ret; +} +module_init(ubi32_nand_spi_er_init); + +/* + * ubi32_nand_spi_er_exit + */ +static void __exit ubi32_nand_spi_er_exit(void) +{ + platform_device_unregister(ubi32_nand_spi_er_device); + platform_driver_unregister(&ubi32_nand_spi_er_driver); +} +module_exit(ubi32_nand_spi_er_exit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick Tjin"); +MODULE_DESCRIPTION("MTD ubi32_nand_spi_er driver for ubicom32 SPI flash controller."); diff --git a/target/linux/ubicom32/files/drivers/net/ubi32-eth.c b/target/linux/ubicom32/files/drivers/net/ubi32-eth.c new file mode 100644 index 000000000..e9c62f462 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/net/ubi32-eth.c @@ -0,0 +1,766 @@ +/* + * drivers/net/ubi32-eth.c + * Ubicom32 ethernet TIO interface driver. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +/* + * ubi32_eth.c + * Ethernet driver for Ip5k/Ip7K + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UBICOM32_USE_NAPI /* define this to use NAPI instead of tasklet */ +//#define UBICOM32_USE_POLLING /* define this to use polling instead of interrupt */ +#include "ubi32-eth.h" + +/* + * TODO: + * mac address from flash + * multicast filter + * ethtool support + * sysfs support + * skb->nrfrag support + * ioctl + * monitor phy status + */ + +extern int ubi32_ocm_skbuf_max, ubi32_ocm_skbuf, ubi32_ddr_skbuf; +static const char *eth_if_name[UBI32_ETH_NUM_OF_DEVICES] = + {"eth_lan", "eth_wan"}; +static struct net_device *ubi32_eth_devices[UBI32_ETH_NUM_OF_DEVICES] = + {NULL, NULL}; +static u8_t mac_addr[UBI32_ETH_NUM_OF_DEVICES][ETH_ALEN] = { + {0x00, 0x03, 0x64, 'l', 'a', 'n'}, + {0x00, 0x03, 0x64, 'w', 'a', 'n'}}; + +#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB)) +static inline struct sk_buff *ubi32_alloc_skb_ocm(struct net_device *dev, unsigned int length) +{ + return __dev_alloc_skb(length, GFP_ATOMIC | __GFP_NOWARN | __GFP_NORETRY | GFP_DMA); +} +#endif + +static inline struct sk_buff *ubi32_alloc_skb(struct net_device *dev, unsigned int length) +{ + return __dev_alloc_skb(length, GFP_ATOMIC | __GFP_NOWARN); +} + +static void ubi32_eth_vp_rxtx_enable(struct net_device *dev) +{ + struct ubi32_eth_private *priv = netdev_priv(dev); + priv->regs->command = UBI32_ETH_VP_CMD_RX_ENABLE | UBI32_ETH_VP_CMD_TX_ENABLE; + priv->regs->int_mask = (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX); + ubicom32_set_interrupt(priv->vp_int_bit); +} + +static void ubi32_eth_vp_rxtx_stop(struct net_device *dev) +{ + struct ubi32_eth_private *priv = netdev_priv(dev); + priv->regs->command = 0; + priv->regs->int_mask = 0; + ubicom32_set_interrupt(priv->vp_int_bit); + + /* Wait for graceful shutdown */ + while (priv->regs->status & (UBI32_ETH_VP_STATUS_RX_STATE | UBI32_ETH_VP_STATUS_TX_STATE)); +} + +/* + * ubi32_eth_tx_done() + */ +static int ubi32_eth_tx_done(struct net_device *dev) +{ + struct ubi32_eth_private *priv; + struct sk_buff *skb; + volatile void *pdata; + struct ubi32_eth_dma_desc *desc; + u32_t count = 0; + + priv = netdev_priv(dev); + + priv->regs->int_status &= ~UBI32_ETH_VP_INT_TX; + while (priv->tx_tail != priv->regs->tx_out) { + pdata = priv->regs->tx_dma_ring[priv->tx_tail]; + BUG_ON(pdata == NULL); + + skb = container_of((void *)pdata, struct sk_buff, cb); + desc = (struct ubi32_eth_dma_desc *)pdata; + if (unlikely(!(desc->status & UBI32_ETH_VP_TX_OK))) { + dev->stats.tx_errors++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + } + dev_kfree_skb_any(skb); + priv->regs->tx_dma_ring[priv->tx_tail] = NULL; + priv->tx_tail = (priv->tx_tail + 1) & TX_DMA_RING_MASK; + count++; + } + + if (unlikely(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) { + spin_lock(&priv->lock); + if (priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL) { + priv->regs->status &= ~UBI32_ETH_VP_STATUS_TX_Q_FULL; + netif_wake_queue(dev); + } + spin_unlock(&priv->lock); + } + return count; +} + +/* + * ubi32_eth_receive() + * To avoid locking overhead, this is called only + * by tasklet when not using NAPI, or + * by NAPI poll when using NAPI. + * return number of frames processed + */ +static int ubi32_eth_receive(struct net_device *dev, int quota) +{ + struct ubi32_eth_private *priv = netdev_priv(dev); + unsigned short rx_in = priv->regs->rx_in; + struct sk_buff *skb; + struct ubi32_eth_dma_desc *desc = NULL; + volatile void *pdata; + + int extra_reserve_adj; + int extra_alloc = UBI32_ETH_RESERVE_SPACE + UBI32_ETH_TRASHED_MEMORY; + int replenish_cnt, count = 0; + int replenish_max = RX_DMA_MAX_QUEUE_SIZE; +#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB)) + if (likely(dev == ubi32_eth_devices[0])) + replenish_max = min(ubi32_ocm_skbuf_max, RX_DMA_MAX_QUEUE_SIZE);; +#endif + + if (unlikely(rx_in == priv->regs->rx_out)) + priv->vp_stats.rx_q_full_cnt++; + + priv->regs->int_status &= ~UBI32_ETH_VP_INT_RX; + while (priv->rx_tail != priv->regs->rx_out) { + if (unlikely(count == quota)) { + /* There is still frame pending to be processed */ + priv->vp_stats.rx_throttle++; + break; + } + + pdata = priv->regs->rx_dma_ring[priv->rx_tail]; + BUG_ON(pdata == NULL); + + desc = (struct ubi32_eth_dma_desc *)pdata; + skb = container_of((void *)pdata, struct sk_buff, cb); + count++; + priv->regs->rx_dma_ring[priv->rx_tail] = NULL; + priv->rx_tail = ((priv->rx_tail + 1) & RX_DMA_RING_MASK); + + /* + * Check only RX_OK bit here. + * The rest of status word is used as timestamp + */ + if (unlikely(!(desc->status & UBI32_ETH_VP_RX_OK))) { + dev->stats.rx_errors++; + dev_kfree_skb_any(skb); + continue; + } + + skb_put(skb, desc->data_len); + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + dev->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; +#ifndef UBICOM32_USE_NAPI + netif_rx(skb); +#else + netif_receive_skb(skb); +#endif + } + + /* fill in more descripor for VP*/ + replenish_cnt = replenish_max - + ((RX_DMA_RING_SIZE + rx_in - priv->rx_tail) & RX_DMA_RING_MASK); + if (replenish_cnt > 0) { +#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB)) + /* + * black magic for perforamnce: + * Try to allocate skb from OCM only for first Ethernet I/F. + * Also limit number of RX buffers to 21 due to limited OCM. + */ + if (likely(dev == ubi32_eth_devices[0])) { + do { + skb = ubi32_alloc_skb_ocm(dev, RX_BUF_SIZE + extra_alloc); + if (!skb) { + break; + } + /* set up dma descriptor */ + ubi32_ocm_skbuf++; + desc = (struct ubi32_eth_dma_desc *)skb->cb; + extra_reserve_adj = + ((u32)skb->data + UBI32_ETH_RESERVE_SPACE + ETH_HLEN) & + (CACHE_LINE_SIZE - 1); + skb_reserve(skb, UBI32_ETH_RESERVE_SPACE - extra_reserve_adj); + desc->data_pointer = skb->data; + desc->buffer_len = RX_BUF_SIZE + UBI32_ETH_TRASHED_MEMORY; + desc->data_len = 0; + desc->status = 0; + priv->regs->rx_dma_ring[rx_in] = desc; + rx_in = (rx_in + 1) & RX_DMA_RING_MASK; + } while (--replenish_cnt > 0); + } +#endif + + while (replenish_cnt-- > 0) { + skb = ubi32_alloc_skb(dev, RX_BUF_SIZE + extra_alloc); + if (!skb) { + priv->vp_stats.rx_alloc_err++; + break; + } + /* set up dma descriptor */ + ubi32_ddr_skbuf++; + desc = (struct ubi32_eth_dma_desc *)skb->cb; + extra_reserve_adj = + ((u32)skb->data + UBI32_ETH_RESERVE_SPACE + ETH_HLEN) & + (CACHE_LINE_SIZE - 1); + skb_reserve(skb, UBI32_ETH_RESERVE_SPACE - extra_reserve_adj); + desc->data_pointer = skb->data; + desc->buffer_len = RX_BUF_SIZE + UBI32_ETH_TRASHED_MEMORY; + desc->data_len = 0; + desc->status = 0; + priv->regs->rx_dma_ring[rx_in] = desc; + rx_in = (rx_in + 1) & RX_DMA_RING_MASK; + } + + wmb(); + priv->regs->rx_in = rx_in; + ubicom32_set_interrupt(priv->vp_int_bit); + } + + if (likely(count > 0)) { + dev->last_rx = jiffies; + } + return count; +} + +#ifdef UBICOM32_USE_NAPI +static int ubi32_eth_napi_poll(struct napi_struct *napi, int budget) +{ + struct ubi32_eth_private *priv = container_of(napi, struct ubi32_eth_private, napi); + struct net_device *dev = priv->dev; + u32_t count; + + if (priv->tx_tail != priv->regs->tx_out) { + ubi32_eth_tx_done(dev); + } + + count = ubi32_eth_receive(dev, budget); + + if (count < budget) { + napi_complete(napi); + priv->regs->int_mask |= (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX); + if ((priv->rx_tail != priv->regs->rx_out) || (priv->tx_tail != priv->regs->tx_out)) { + if (napi_reschedule(napi)) { + priv->regs->int_mask = 0; + } + } + } + return count; +} + +#else +static void ubi32_eth_do_tasklet(unsigned long arg) +{ + struct net_device *dev = (struct net_device *)arg; + struct ubi32_eth_private *priv = netdev_priv(dev); + + if (priv->tx_tail != priv->regs->tx_out) { + ubi32_eth_tx_done(dev); + } + + /* always call receive to process new RX frame as well as replenish RX buffers */ + ubi32_eth_receive(dev, UBI32_RX_BOUND); + + priv->regs->int_mask |= (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX); + if ((priv->rx_tail != priv->regs->rx_out) || (priv->tx_tail != priv->regs->tx_out)) { + priv->regs->int_mask = 0; + tasklet_schedule(&priv->tsk); + } +} +#endif + +#if defined(UBICOM32_USE_POLLING) +static struct timer_list eth_poll_timer; + +static void ubi32_eth_poll(unsigned long arg) +{ + struct net_device *dev; + struct ubi32_eth_private *priv; + int i; + + for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) { + dev = ubi32_eth_devices[i]; + if (dev && (dev->flags & IFF_UP)) { + priv = netdev_priv(dev); +#ifdef UBICOM32_USE_NAPI + napi_schedule(&priv->napi); +#else + tasklet_schedule(&priv->tsk); +#endif + } + } + + eth_poll_timer.expires = jiffies + 2; + add_timer(ð_poll_timer); +} + +#else +static irqreturn_t ubi32_eth_interrupt(int irq, void *dev_id) +{ + struct ubi32_eth_private *priv; + + struct net_device *dev = (struct net_device *)dev_id; + BUG_ON(irq != dev->irq); + + priv = netdev_priv(dev); + if (unlikely(!(priv->regs->int_status & priv->regs->int_mask))) { + return IRQ_NONE; + } + + /* + * Disable port interrupt + */ +#ifdef UBICOM32_USE_NAPI + if (napi_schedule_prep(&priv->napi)) { + priv->regs->int_mask = 0; + __napi_schedule(&priv->napi); + } +#else + priv->regs->int_mask = 0; + tasklet_schedule(&priv->tsk); +#endif + return IRQ_HANDLED; +} +#endif + +/* + * ubi32_eth_open + */ +static int ubi32_eth_open(struct net_device *dev) +{ + struct ubi32_eth_private *priv = netdev_priv(dev); + int err; + + printk(KERN_INFO "eth open %s\n",dev->name); +#ifndef UBICOM32_USE_POLLING + /* request_region() */ + err = request_irq(dev->irq, ubi32_eth_interrupt, IRQF_DISABLED, dev->name, dev); + if (err) { + printk(KERN_WARNING "fail to request_irq %d\n",err); + return -ENODEV; + } +#endif +#ifdef UBICOM32_USE_NAPI + napi_enable(&priv->napi); +#else + tasklet_init(&priv->tsk, ubi32_eth_do_tasklet, (unsigned long)dev); +#endif + + /* call receive to supply RX buffers */ + ubi32_eth_receive(dev, RX_DMA_MAX_QUEUE_SIZE); + + /* check phy status and call netif_carrier_on */ + ubi32_eth_vp_rxtx_enable(dev); + netif_start_queue(dev); + return 0; +} + +static int ubi32_eth_close(struct net_device *dev) +{ + struct ubi32_eth_private *priv = netdev_priv(dev); + volatile void *pdata; + struct sk_buff *skb; + +#ifndef UBICOM32_USE_POLLING + free_irq(dev->irq, dev); +#endif + netif_stop_queue(dev); /* can't transmit any more */ +#ifdef UBICOM32_USE_NAPI + napi_disable(&priv->napi); +#else + tasklet_kill(&priv->tsk); +#endif + ubi32_eth_vp_rxtx_stop(dev); + + /* + * RX clean up + */ + while (priv->rx_tail != priv->regs->rx_in) { + pdata = priv->regs->rx_dma_ring[priv->rx_tail]; + skb = container_of((void *)pdata, struct sk_buff, cb); + priv->regs->rx_dma_ring[priv->rx_tail] = NULL; + dev_kfree_skb_any(skb); + priv->rx_tail = ((priv->rx_tail + 1) & RX_DMA_RING_MASK); + } + priv->regs->rx_in = 0; + priv->regs->rx_out = priv->regs->rx_in; + priv->rx_tail = priv->regs->rx_in; + + /* + * TX clean up + */ + BUG_ON(priv->regs->tx_out != priv->regs->tx_in); + ubi32_eth_tx_done(dev); + BUG_ON(priv->tx_tail != priv->regs->tx_in); + priv->regs->tx_in = 0; + priv->regs->tx_out = priv->regs->tx_in; + priv->tx_tail = priv->regs->tx_in; + + return 0; +} + +/* + * ubi32_eth_set_config + */ +static int ubi32_eth_set_config(struct net_device *dev, struct ifmap *map) +{ + /* if must to down to config it */ + printk(KERN_INFO "set_config %x\n", dev->flags); + if (dev->flags & IFF_UP) + return -EBUSY; + + /* I/O and IRQ can not be changed */ + if (map->base_addr != dev->base_addr) { + printk(KERN_WARNING "%s: Can't change I/O address\n", dev->name); + return -EOPNOTSUPP; + } + +#ifndef UBICOM32_USE_POLLING + if (map->irq != dev->irq) { + printk(KERN_WARNING "%s: Can't change IRQ\n", dev->name); + return -EOPNOTSUPP; + } +#endif + + /* ignore other fields */ + return 0; +} + +static int ubi32_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ubi32_eth_private *priv = netdev_priv(dev); + struct ubi32_eth_dma_desc *desc = NULL; + unsigned short space, tx_in; + + tx_in = priv->regs->tx_in; + + dev->trans_start = jiffies; /* save the timestamp */ + space = TX_DMA_RING_MASK - ((TX_DMA_RING_SIZE + tx_in - priv->tx_tail) & TX_DMA_RING_MASK); + + if (unlikely(space == 0)) { + if (!(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) { + spin_lock(&priv->lock); + if (!(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) { + priv->regs->status |= UBI32_ETH_VP_STATUS_TX_Q_FULL; + priv->vp_stats.tx_q_full_cnt++; + netif_stop_queue(dev); + } + spin_unlock(&priv->lock); + } + + /* give both HW and this driver an extra trigger */ + priv->regs->int_mask |= UBI32_ETH_VP_INT_TX; +#ifndef UBICOM32_USE_POLLING + ubicom32_set_interrupt(dev->irq); +#endif + ubicom32_set_interrupt(priv->vp_int_bit); + + return NETDEV_TX_BUSY; + } + + /*still have room */ + desc = (struct ubi32_eth_dma_desc *)skb->cb; + desc->data_pointer = skb->data; + desc->data_len = skb->len; + priv->regs->tx_dma_ring[tx_in] = desc; + tx_in = ((tx_in + 1) & TX_DMA_RING_MASK); + wmb(); + priv->regs->tx_in = tx_in; + /* kick the HRT */ + ubicom32_set_interrupt(priv->vp_int_bit); + + return NETDEV_TX_OK; +} + +/* + * Deal with a transmit timeout. + */ +static void ubi32_eth_tx_timeout (struct net_device *dev) +{ + struct ubi32_eth_private *priv = netdev_priv(dev); + dev->stats.tx_errors++; + priv->regs->int_mask |= UBI32_ETH_VP_INT_TX; +#ifndef UBICOM32_USE_POLLING + ubicom32_set_interrupt(dev->irq); +#endif + ubicom32_set_interrupt(priv->vp_int_bit); +} + +static int ubi32_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct ubi32_eth_private *priv = netdev_priv(dev); + struct mii_ioctl_data *data = if_mii(rq); + + printk(KERN_INFO "ioctl %s, %d\n", dev->name, cmd); + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = 0; + break; + + case SIOCGMIIREG: + if ((data->reg_num & 0x1F) == MII_BMCR) { + /* Make up MII control register value from what we know */ + data->val_out = 0x0000 + | ((priv->regs->status & UBI32_ETH_VP_STATUS_DUPLEX) + ? BMCR_FULLDPLX : 0) + | ((priv->regs->status & UBI32_ETH_VP_STATUS_SPEED100) + ? BMCR_SPEED100 : 0) + | ((priv->regs->status & UBI32_ETH_VP_STATUS_SPEED1000) + ? BMCR_SPEED1000 : 0); + } else if ((data->reg_num & 0x1F) == MII_BMSR) { + /* Make up MII status register value from what we know */ + data->val_out = + (BMSR_100FULL|BMSR_100HALF|BMSR_10FULL|BMSR_10HALF) + | ((priv->regs->status & UBI32_ETH_VP_STATUS_LINK) + ? BMSR_LSTATUS : 0); + } else { + return -EIO; + } + break; + + case SIOCSMIIREG: + return -EOPNOTSUPP; + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/* + * Return statistics to the caller + */ +static struct net_device_stats *ubi32_eth_get_stats(struct net_device *dev) +{ + return &dev->stats; +} + + +static int ubi32_eth_change_mtu(struct net_device *dev, int new_mtu) +{ + struct ubi32_eth_private *priv = netdev_priv(dev); + unsigned long flags; + + if ((new_mtu < 68) || (new_mtu > 1500)) + return -EINVAL; + + spin_lock_irqsave(&priv->lock, flags); + dev->mtu = new_mtu; + spin_unlock_irqrestore(&priv->lock, flags); + printk(KERN_INFO "set mtu to %d", new_mtu); + return 0; +} + +/* + * ubi32_eth_cleanup: unload the module + */ +void ubi32_eth_cleanup(void) +{ + struct ubi32_eth_private *priv; + struct net_device *dev; + int i; + + for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) { + dev = ubi32_eth_devices[i]; + if (dev) { + priv = netdev_priv(dev); + kfree(priv->regs->tx_dma_ring); + unregister_netdev(dev); + free_netdev(dev); + ubi32_eth_devices[i] = NULL; + } + } +} + + static const struct net_device_ops ubi32_netdev_ops = { + .ndo_open = ubi32_eth_open, + .ndo_stop = ubi32_eth_close, + .ndo_start_xmit = ubi32_eth_start_xmit, + .ndo_tx_timeout = ubi32_eth_tx_timeout, + .ndo_do_ioctl = ubi32_eth_ioctl, + .ndo_change_mtu = ubi32_eth_change_mtu, + .ndo_set_config = ubi32_eth_set_config, + .ndo_get_stats = ubi32_eth_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + }; + +int ubi32_eth_init_module(void) +{ + struct ethtionode *eth_node; + struct net_device *dev; + struct ubi32_eth_private *priv; + int i, err; + + /* + * Device allocation. + */ + err = 0; + for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) { + /* + * See if the eth_vp is in the device tree. + */ + eth_node = (struct ethtionode *)devtree_find_node(eth_if_name[i]); + if (!eth_node) { + printk(KERN_INFO "%s does not exist\n", eth_if_name[i]); + continue; + } + + eth_node->tx_dma_ring = (struct ubi32_eth_dma_desc **)kmalloc( + sizeof(struct ubi32_eth_dma_desc *) * + (TX_DMA_RING_SIZE + RX_DMA_RING_SIZE), + GFP_ATOMIC | __GFP_NOWARN | __GFP_NORETRY | GFP_DMA); + + if (eth_node->tx_dma_ring == NULL) { + eth_node->tx_dma_ring = (struct ubi32_eth_dma_desc **)kmalloc( + sizeof(struct ubi32_eth_dma_desc *) * + (TX_DMA_RING_SIZE + RX_DMA_RING_SIZE), GFP_KERNEL); + printk(KERN_INFO "fail to allocate from OCM\n"); + } + + if (!eth_node->tx_dma_ring) { + err = -ENOMEM; + break; + } + eth_node->rx_dma_ring = eth_node->tx_dma_ring + TX_DMA_RING_SIZE; + eth_node->tx_sz = TX_DMA_RING_SIZE - 1; + eth_node->rx_sz = RX_DMA_RING_SIZE - 1; + + dev = alloc_etherdev(sizeof(struct ubi32_eth_private)); + if (!dev) { + kfree(eth_node->tx_dma_ring); + err = -ENOMEM; + break; + } + priv = netdev_priv(dev); + priv->dev = dev; + + /* + * This just fill in some default Ubicom MAC address + */ + memcpy(dev->dev_addr, mac_addr[i], ETH_ALEN); + memset(dev->broadcast, 0xff, ETH_ALEN); + + priv->regs = eth_node; + priv->regs->command = 0; + priv->regs->int_mask = 0; + priv->regs->int_status = 0; + priv->regs->tx_out = 0; + priv->regs->rx_out = 0; + priv->regs->tx_in = 0; + priv->regs->rx_in = 0; + priv->rx_tail = 0; + priv->tx_tail = 0; + + priv->vp_int_bit = eth_node->dn.sendirq; + dev->irq = eth_node->dn.recvirq; + + spin_lock_init(&priv->lock); + + dev->netdev_ops = &ubi32_netdev_ops; + + dev->watchdog_timeo = UBI32_ETH_VP_TX_TIMEOUT; +#ifdef UBICOM32_USE_NAPI + netif_napi_add(dev, &priv->napi, ubi32_eth_napi_poll, UBI32_ETH_NAPI_WEIGHT); +#endif + err = register_netdev(dev); + if (err) { + printk(KERN_WARNING "Failed to register netdev %s\n", eth_if_name[i]); + //release_region(); + free_netdev(dev); + kfree(eth_node->tx_dma_ring); + break; + } + + ubi32_eth_devices[i] = dev; + printk(KERN_INFO "%s vp_base:0x%p, tio_int:%d irq:%d feature:0x%lx\n", + dev->name, priv->regs, eth_node->dn.sendirq, dev->irq, dev->features); + } + + if (err) { + ubi32_eth_cleanup(); + return err; + } + + if (!ubi32_eth_devices[0] && !ubi32_eth_devices[1]) { + return -ENODEV; + } + +#if defined(UBICOM32_USE_POLLING) + init_timer(ð_poll_timer); + eth_poll_timer.function = ubi32_eth_poll; + eth_poll_timer.data = (unsigned long)0; + eth_poll_timer.expires = jiffies + 2; + add_timer(ð_poll_timer); +#endif + + return 0; +} + +module_init(ubi32_eth_init_module); +module_exit(ubi32_eth_cleanup); + +MODULE_AUTHOR("Kan Yan, Greg Ren"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/drivers/net/ubi32-eth.h b/target/linux/ubicom32/files/drivers/net/ubi32-eth.h new file mode 100644 index 000000000..c25500143 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/net/ubi32-eth.h @@ -0,0 +1,132 @@ +/* + * drivers/net/ubi32-eth.h + * Ubicom32 ethernet TIO interface driver definitions. + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#ifndef _UBI32_ETH_H +#define _UBI32_ETH_H + +#include + +#define UBI32_ETH_NUM_OF_DEVICES 2 + +/* + * Number of bytes trashed beyond the packet data. + */ +#define UBI32_ETH_TRASHED_MEMORY (CACHE_LINE_SIZE + ETH_HLEN - 1) + +/* + * Linux already reserves NET_SKB_PAD bytes of headroom in each sk_buff. + * We want to be able to reserve at least one cache line to align Ethernet + * and IP header to cache line. + * Note that the TIO expects a CACHE_LINE_SIZE - ETH_HLEN aligned Ethernet + * header, while satisfies NET_IP_ALIGN (= 2) automatically. + * (NET_SKB_PAD is 16, NET_IP_ALIGN is 2, CACHE_LINE_SIZE is 32). + * You can add more space by making UBI32_ETH_RESERVE_EXTRA != 0. + */ +#define UBI32_ETH_RESERVE_EXTRA (1 * CACHE_LINE_SIZE) +#define UBI32_ETH_RESERVE_SPACE (UBI32_ETH_RESERVE_EXTRA + CACHE_LINE_SIZE) + +struct ubi32_eth_dma_desc { + volatile void *data_pointer; /* pointer to the buffer */ + volatile u16 buffer_len; /* the buffer size */ + volatile u16 data_len; /* actual frame length */ + volatile u32 status; /* bit0: status to be update by VP; bit[31:1] time stamp */ +}; + +#define TX_DMA_RING_SIZE (1<<8) +#define TX_DMA_RING_MASK (TX_DMA_RING_SIZE - 1) +#define RX_DMA_RING_SIZE (1<<8) +#define RX_DMA_RING_MASK (RX_DMA_RING_SIZE - 1) + +#define RX_DMA_MAX_QUEUE_SIZE (RX_DMA_RING_SIZE - 1) /* no more than (RX_DMA_RING_SIZE - 1) */ +#define RX_MAX_PKT_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN) +#define RX_MIN_PKT_SIZE ETH_ZLEN +#define RX_BUF_SIZE (RX_MAX_PKT_SIZE + VLAN_HLEN) /* allow double VLAN tag */ + +#define UBI32_ETH_VP_TX_TIMEOUT (10*HZ) + +struct ubi32_eth_vp_stats { + u32 rx_alloc_err; + u32 tx_q_full_cnt; + u32 rx_q_full_cnt; + u32 rx_throttle; +}; + +struct ubi32_eth_private { + struct net_device *dev; + struct ubi32_eth_vp_stats vp_stats; + spinlock_t lock; +#ifdef UBICOM32_USE_NAPI + struct napi_struct napi; +#else + struct tasklet_struct tsk; +#endif + struct ethtionode *regs; + u16 rx_tail; + u16 tx_tail; + u32 vp_int_bit; +}; + +struct ethtionode { + struct devtree_node dn; + volatile u16 command; + volatile u16 status; + volatile u16 int_mask; /* interrupt mask */ + volatile u16 int_status; /* interrupt mask */ + volatile u16 tx_in; /* owned by driver */ + volatile u16 tx_out; /* owned by vp */ + volatile u16 rx_in; /* owned by driver */ + volatile u16 rx_out; /* owned by vp */ + u16 tx_sz; /* owned by driver */ + u16 rx_sz; /* owned by driver */ + struct ubi32_eth_dma_desc **tx_dma_ring; + struct ubi32_eth_dma_desc **rx_dma_ring; +}; + +#define UBI32_ETH_VP_STATUS_LINK (1<<0) +#define UBI32_ETH_VP_STATUS_SPEED100 (0x1<<1) +#define UBI32_ETH_VP_STATUS_SPEED1000 (0x1<<2) +#define UBI32_ETH_VP_STATUS_DUPLEX (0x1<<3) +#define UBI32_ETH_VP_STATUS_FLOW_CTRL (0x1<<4) + +#define UBI32_ETH_VP_STATUS_RX_STATE (0x1<<5) +#define UBI32_ETH_VP_STATUS_TX_STATE (0x1<<6) + +#define UBI32_ETH_VP_STATUS_TX_Q_FULL (1<<8) + +#define UBI32_ETH_VP_INT_RX (1<<0) +#define UBI32_ETH_VP_INT_TX (1<<1) + +#define UBI32_ETH_VP_CMD_RX_ENABLE (1<<0) +#define UBI32_ETH_VP_CMD_TX_ENABLE (1<<1) + +#define UBI32_ETH_VP_RX_OK (1<<0) +#define UBI32_ETH_VP_TX_OK (1<<1) + +#define UBI32_TX_BOUND TX_DMA_RING_SIZE +#define UBI32_RX_BOUND 64 +#define UBI32_ETH_NAPI_WEIGHT 64 /* for GigE */ +#endif diff --git a/target/linux/ubicom32/files/drivers/serial/ubi32_mailbox.c b/target/linux/ubicom32/files/drivers/serial/ubi32_mailbox.c new file mode 100644 index 000000000..f14fcdfd9 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/serial/ubi32_mailbox.c @@ -0,0 +1,938 @@ +/* + * drivers/serial/ubi32_mailbox.c + * Ubicom32 On-Chip Mailbox Driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SERIAL_UBICOM_BAUDRATE 115200 +#define SERIAL_UBICOM_DATA_BIT 8 /* Fixed parameter - do not change */ +#define SERIAL_UBICOM_PAR_BIT 0 /* Fixed parameter - do not change */ +#define SERIAL_UBICOM_STOP_BIT 1 /* Fixed parameter - do not change */ + +/* UART name and device definitions */ +#define UBI32_MAILBOX_NAME "ttyUM" // XXX +#define UBI32_MAILBOX_MAJOR 207 // XXX +#define UBI32_MAILBOX_MINOR 64 + +#define PORT_UBI32_MAILBOX 1235 +#define NR_PORTS 1 + +#define get_sclk() 0 + +struct ubi32_mailbox_port { + struct uart_port port; + /* + * NOTE (rkeller): + * the uart port is wrapped in another structure in case we need to hold more state than + * what we can hold in the uart_port. + * Not sure if we need this, I took over the concept from the blackfin driver. + */ +} ubi32_mailbox_ports[NR_PORTS]; + +struct ubi32_mailbox_resource { + int uart_base_addr; + int uart_irq; +} ubi32_mailbox_resource[NR_PORTS] = { + /* + * uart_base_addr has to be non-NULL because it is put in the uart_port membase. + * If membase if null the kernel skips the configuration and our port_type never gets set. + */ + {ISD_MAILBOX_BASE, ISD_MAILBOX_INT} +}; + +static volatile struct ubicom32_isd_mailbox { + volatile u32_t in; + volatile u32_t out; + volatile u32_t status; +} *ubi32_mailbox = (struct ubicom32_isd_mailbox *)ISD_MAILBOX_BASE; + +static void ubi32_mailbox_tx_chars(struct ubi32_mailbox_port *uart); + +static void ubi32_mailbox_mctrl_check(struct ubi32_mailbox_port *uart); + +#define TRUE 1 +#define FALSE 0 + +static int mailbox_console_flg = TRUE; +static int num_timeouts = 0; + +/* + * dummy functions and defined to be able to compile the Blackfin code + */ +#define UART_GET_LSR(port) (1) +#define UART_PUT_LSR(port, bits) +#define UART_CLEAR_LSR(port) (1) +#define TEMT 1 +#define TFI 1 +#define BI 1 +#define PE 1 +#define OE 1 +#define FE 1 +#define THRE 1 +#define DR 1 +#define UART_GET_LCR(port) (1) +#define UART_PUT_LCR(port, bits) +#define SB 1 +#define STB 1 +#define PEN 1 +#define EPS 1 +#define STP 1 +#define WLS(n) 0 +#define UART_GET_IER(port) (1) +#define UART_SET_IER(port, bits) +#define UART_CLEAR_IER(port, bits) +#define ETBEI 0 +#define ERBFI 0 +#define UART_GET_CHAR(port) ubi32_mailbox_get_char() +#define UART_PUT_CHAR(port, ch) ubi32_mailbox_put_char(ch) +#define SSYNC() +#define UART_GET_DLL(port) 0 +#define UART_PUT_DLL(port, ch) +#define UART_GET_DLH(port) 0 +#define UART_PUT_DLH(port, ch) +#define UART_GET_GCTL(port) (0) +#define UART_PUT_GCTL(port, ch) +#define UCEN 1 + +/* + * ubi32_mailbox_get_char_avail() + */ +static int ubi32_mailbox_get_char_avail(void) +{ + return !(ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY); +} + +/* + * ubi32_mailbox_get_char() + */ +static u32_t ubi32_mailbox_get_char(void) +{ + if (mailbox_console_flg == TRUE) { + /* + * Mailbox console is connected. + */ + while (ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY); + return ubi32_mailbox->in & 0xff; + } + + /* + * Mailbox console was not connected. + */ + if (ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY) { + return 0xff; + } + + /* + * Mailbox console is connecting. + */ + mailbox_console_flg = TRUE; + num_timeouts = 0; + return ubi32_mailbox->in & 0xff; +} + +#define MAILBOX_MAX_ATTEMPTS 1000000 +#define MAILBOX_MAX_TIMEOUTS 5 +/* + * ubi32_mailbox_put_char() + */ +static void ubi32_mailbox_put_char(u32_t v) +{ + /* + * Wait to be able to output. + */ + u32_t num_attempts = 0; + + if(mailbox_console_flg == TRUE) { + while(num_attempts++ < MAILBOX_MAX_ATTEMPTS) { + if(ubi32_mailbox->status & ISD_MAILBOX_STATUS_OUT_EMPTY) { + break; + } + } + + /* + * If timed out more than 5 times on send, mailbox console is disconnected now. + */ + if (num_attempts > MAILBOX_MAX_ATTEMPTS) { + if (num_timeouts++ > MAILBOX_MAX_TIMEOUTS) { + mailbox_console_flg = FALSE; + } + } + } + + asm volatile( + "pipe_flush 0 \n\t" + "pipe_flush 0 \n\t" + "pipe_flush 0 \n\t" + "pipe_flush 0 \n\t" + "pipe_flush 0 \n\t" + "pipe_flush 0 \n\t" + "pipe_flush 0 \n\t" + ); + + ubi32_mailbox->out = v & 0xff; +} + +static void ubi32_mailbox_hw_init(struct ubi32_mailbox_port *uart) +{ +// NOTE: It does not do any good to do these here because we are running on the linux hardware thread, +// and these have to be called on the ldsr thread. +// ubicom32_clear_interrupt(ISD_MAILBOX_INT); +// ubicom32_enable_interrupt(ISD_MAILBOX_INT); +} + +/* + * interrupts are disabled on entry + */ +static void ubi32_mailbox_stop_tx(struct uart_port *port) +{ +// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; +// struct circ_buf *xmit = &uart->port.info->xmit; + + while (!(UART_GET_LSR(uart) & TEMT)) + cpu_relax(); + + /* Clear TFI bit */ + UART_PUT_LSR(uart, TFI); + UART_CLEAR_IER(uart, ETBEI); +} + +/* + * port is locked and interrupts are disabled + */ +static void ubi32_mailbox_start_tx(struct uart_port *port) +{ + struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + + UART_SET_IER(uart, ETBEI); + + ubi32_mailbox_tx_chars(uart); +} + +/* + * Interrupts are enabled + */ +static void ubi32_mailbox_stop_rx(struct uart_port *port) +{ +// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + UART_CLEAR_IER(uart, ERBFI); +} + +/* + * Set the modem control timer to fire immediately. + */ +static void ubi32_mailbox_enable_ms(struct uart_port *port) +{ +} + +static void ubi32_mailbox_rx_chars(struct ubi32_mailbox_port *uart) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) + struct uart_state *state = uart->port.state; + struct tty_struct *tty = state->port.tty; +#else + struct uart_info *info = uart->port.info; + struct tty_struct *tty = info->port.tty; +#endif + unsigned int status, ch, flg; + + status = 0; // XXX? UART_GET_LSR(uart); + UART_CLEAR_LSR(uart); + + ch = UART_GET_CHAR(uart); + + if(ch == 0xff) + return; + + uart->port.icount.rx++; + + if (status & BI) { + uart->port.icount.brk++; + if (uart_handle_break(&uart->port)) + goto ignore_char; + status &= ~(PE | FE); + } + if (status & PE) + uart->port.icount.parity++; + if (status & OE) + uart->port.icount.overrun++; + if (status & FE) + uart->port.icount.frame++; + + status &= uart->port.read_status_mask; + + if (status & BI) + flg = TTY_BREAK; + else if (status & PE) + flg = TTY_PARITY; + else if (status & FE) + flg = TTY_FRAME; + else + flg = TTY_NORMAL; + + if (uart_handle_sysrq_char(&uart->port, ch)) + goto ignore_char; + + uart_insert_char(&uart->port, status, OE, ch, flg); + + ignore_char: + tty_flip_buffer_push(tty); +} + +static void ubi32_mailbox_tx_chars(struct ubi32_mailbox_port *uart) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) + struct circ_buf *xmit = &uart->port.state->xmit; +#else + struct circ_buf *xmit = &uart->port.info->xmit; +#endif + + if (uart->port.x_char) { + UART_PUT_CHAR(uart, uart->port.x_char); + uart->port.icount.tx++; + uart->port.x_char = 0; + } + /* + * Check the modem control lines before + * transmitting anything. + */ + ubi32_mailbox_mctrl_check(uart); + + if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { + ubi32_mailbox_stop_tx(&uart->port); + return; + } + + while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) { + UART_PUT_CHAR(uart, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + uart->port.icount.tx++; + SSYNC(); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uart->port); + + if (uart_circ_empty(xmit)) + ubi32_mailbox_stop_tx(&uart->port); +} + +static irqreturn_t ubi32_mailbox_isr(int irq, void *dev_id) +{ + struct ubi32_mailbox_port *uart = dev_id; + + spin_lock(&uart->port.lock); + + //XXX?while (UART_GET_LSR(uart) & DR) + + /* + * RX process + */ + while (ubi32_mailbox_get_char_avail()) { + ubi32_mailbox_rx_chars(uart); + } + +#if 0 + /* + * TX process + */ + if (this_uart.tx_in == this_uart.tx_out) { + UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_mask &= ~IO_PORTX_INT_SERDES_TXBE; + } else if (UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_status & IO_PORTX_INT_SERDES_TXBE) { + uart_ubicom32_send(this_uart.tx_buf[this_uart.tx_out & (SERIAL_UBICOM_BUF_SIZE - 1)]); + this_uart.tx_out++; + UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_mask |= IO_PORTX_INT_SERDES_TXBE; + } +#endif + + spin_unlock(&uart->port.lock); + + return IRQ_HANDLED; +} +#if 0 +static irqreturn_t ubi32_mailbox_tx_int(int irq, void *dev_id) +{ + struct ubi32_mailbox_port *uart = dev_id; + + spin_lock(&uart->port.lock); + if (UART_GET_LSR(uart) & THRE) + ubi32_mailbox_tx_chars(uart); + spin_unlock(&uart->port.lock); + + return IRQ_HANDLED; +} +#endif + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int ubi32_mailbox_tx_empty(struct uart_port *port) +{ +// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + unsigned short lsr; + + lsr = UART_GET_LSR(uart); + if (lsr & TEMT) + return TIOCSER_TEMT; + else + return 0; +} + +static unsigned int ubi32_mailbox_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void ubi32_mailbox_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +/* + * Handle any change of modem status signal since we were last called. + */ +static void ubi32_mailbox_mctrl_check(struct ubi32_mailbox_port *uart) +{ +} + +/* + * Interrupts are always disabled. + */ +static void ubi32_mailbox_break_ctl(struct uart_port *port, int break_state) +{ +// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + u16 lcr = UART_GET_LCR(uart); + if (break_state) + lcr |= SB; + else + lcr &= ~SB; + UART_PUT_LCR(uart, lcr); + SSYNC(); +} + +static int ubi32_mailbox_startup(struct uart_port *port) +{ + struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + + if (request_irq(uart->port.irq, ubi32_mailbox_isr, IRQF_DISABLED, + "UBI32_MAILBOX", uart)) { + printk(KERN_NOTICE "Unable to attach Ubicom32 SERDES interrupt\n"); + return -EBUSY; + } + + UART_SET_IER(uart, ERBFI); + return 0; +} + +static void ubi32_mailbox_shutdown(struct uart_port *port) +{ + struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + + free_irq(uart->port.irq, uart); +} + +static void +ubi32_mailbox_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + unsigned long flags; + unsigned int baud, quot; + unsigned short val, ier, lsr, lcr = 0; + + switch (termios->c_cflag & CSIZE) { + case CS8: + lcr = WLS(8); + break; + case CS7: + lcr = WLS(7); + break; + case CS6: + lcr = WLS(6); + break; + case CS5: + lcr = WLS(5); + break; + default: + printk(KERN_ERR "%s: word lengh not supported\n", + __FUNCTION__); + } + + if (termios->c_cflag & CSTOPB) + lcr |= STB; + if (termios->c_cflag & PARENB) + lcr |= PEN; + if (!(termios->c_cflag & PARODD)) + lcr |= EPS; + if (termios->c_cflag & CMSPAR) + lcr |= STP; + + port->read_status_mask = OE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= (FE | PE); + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= BI; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= FE | PE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= OE; + } + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + spin_lock_irqsave(&uart->port.lock, flags); + + do { + lsr = UART_GET_LSR(uart); + } while (!(lsr & TEMT)); + + /* Disable UART */ + ier = UART_GET_IER(uart); + UART_CLEAR_IER(uart, 0xF); + + UART_PUT_DLL(uart, quot & 0xFF); + SSYNC(); + UART_PUT_DLH(uart, (quot >> 8) & 0xFF); + SSYNC(); + + UART_PUT_LCR(uart, lcr); + + /* Enable UART */ + UART_SET_IER(uart, ier); + + val = UART_GET_GCTL(uart); + val |= UCEN; + UART_PUT_GCTL(uart, val); + + spin_unlock_irqrestore(&uart->port.lock, flags); +} + +static const char *ubi32_mailbox_type(struct uart_port *port) +{ + struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + + return uart->port.type == PORT_UBI32_MAILBOX ? "UBI32_MAILBOX" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void ubi32_mailbox_release_port(struct uart_port *port) +{ +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int ubi32_mailbox_request_port(struct uart_port *port) +{ + return 0; +} + +/* + * Configure/autoconfigure the port. + */ +static void ubi32_mailbox_config_port(struct uart_port *port, int flags) +{ + struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + + if (flags & UART_CONFIG_TYPE && ubi32_mailbox_request_port(&uart->port) == 0) + uart->port.type = PORT_UBI32_MAILBOX; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + * The only change we allow are to the flags and type, and + * even then only between PORT_UBI32_MAILBOX and PORT_UNKNOWN + */ +static int +ubi32_mailbox_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return 0; +} + +static struct uart_ops ubi32_mailbox_pops = { + .tx_empty = ubi32_mailbox_tx_empty, + .set_mctrl = ubi32_mailbox_set_mctrl, + .get_mctrl = ubi32_mailbox_get_mctrl, + .stop_tx = ubi32_mailbox_stop_tx, + .start_tx = ubi32_mailbox_start_tx, + .stop_rx = ubi32_mailbox_stop_rx, + .enable_ms = ubi32_mailbox_enable_ms, + .break_ctl = ubi32_mailbox_break_ctl, + .startup = ubi32_mailbox_startup, + .shutdown = ubi32_mailbox_shutdown, + .set_termios = ubi32_mailbox_set_termios, + .type = ubi32_mailbox_type, + .release_port = ubi32_mailbox_release_port, + .request_port = ubi32_mailbox_request_port, + .config_port = ubi32_mailbox_config_port, + .verify_port = ubi32_mailbox_verify_port, +}; + +static void __init ubi32_mailbox_init_ports(void) +{ + static int first = 1; + int i; + + if (!first) + return; + first = 0; + + for (i = 0; i < NR_PORTS; i++) { + ubi32_mailbox_ports[i].port.uartclk = get_sclk(); + ubi32_mailbox_ports[i].port.ops = &ubi32_mailbox_pops; + ubi32_mailbox_ports[i].port.line = i; + ubi32_mailbox_ports[i].port.iotype = UPIO_MEM; + ubi32_mailbox_ports[i].port.membase = + (void __iomem *)ubi32_mailbox_resource[i].uart_base_addr; + ubi32_mailbox_ports[i].port.mapbase = + ubi32_mailbox_resource[i].uart_base_addr; + ubi32_mailbox_ports[i].port.irq = + ubi32_mailbox_resource[i].uart_irq; + ubi32_mailbox_ports[i].port.flags = UPF_BOOT_AUTOCONF; + spin_lock_init(&ubi32_mailbox_ports[i].port.lock); + + ubi32_mailbox_hw_init(&ubi32_mailbox_ports[i]); + } + +} + +#ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE +/* + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init +ubi32_mailbox_console_get_options(struct ubi32_mailbox_port *uart, int *baud, + int *parity, int *bits) +{ + unsigned short status; + + status = UART_GET_IER(uart) & (ERBFI | ETBEI); + if (status == (ERBFI | ETBEI)) { + /* ok, the port was enabled */ + unsigned short lcr; + unsigned short dlh, dll; + + lcr = UART_GET_LCR(uart); + + *parity = 'n'; + if (lcr & PEN) { + if (lcr & EPS) + *parity = 'e'; + else + *parity = 'o'; + } + switch (lcr & 0x03) { + case 0: *bits = 5; break; + case 1: *bits = 6; break; + case 2: *bits = 7; break; + case 3: *bits = 8; break; + } + + dll = UART_GET_DLL(uart); + dlh = UART_GET_DLH(uart); + + *baud = get_sclk() / (16*(dll | dlh << 8)); + } + pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits); +} +#endif + +#if defined(CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE) || defined(CONFIG_EARLY_PRINTK) +static struct uart_driver ubi32_mailbox_reg; + +static int __init +ubi32_mailbox_console_setup(struct console *co, char *options) +{ + struct ubi32_mailbox_port *uart; +# ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE + int baud = SERIAL_UBICOM_BAUDRATE; + int bits = 8; + int parity = 'n'; + int flow = 'n'; +# endif + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= NR_PORTS) + co->index = 0; + uart = &ubi32_mailbox_ports[co->index]; + +# ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + ubi32_mailbox_console_get_options(uart, &baud, &parity, &bits); + + //JB return uart_set_options(&uart->port, co, baud, parity, bits, flow); + return 0; +# else + return 0; +# endif +} +#endif /* defined (CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE) || + defined (CONFIG_EARLY_PRINTK) */ + +#ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE +static void ubi32_mailbox_console_putchar(struct uart_port *port, int ch) +{ +// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; + while (!(UART_GET_LSR(uart) & THRE)) + barrier(); + UART_PUT_CHAR(uart, ch); + SSYNC(); +} + +/* + * Interrupts are disabled on entering + */ +static void +ubi32_mailbox_console_write(struct console *co, const char *s, unsigned int count) +{ + struct ubi32_mailbox_port *uart = &ubi32_mailbox_ports[co->index]; + unsigned long flags = 0; + + spin_lock_irqsave(&uart->port.lock, flags); + uart_console_write(&uart->port, s, count, ubi32_mailbox_console_putchar); + spin_unlock_irqrestore(&uart->port.lock, flags); + +} + +static struct console ubi32_mailbox_console = { + .name = UBI32_MAILBOX_NAME, + .write = ubi32_mailbox_console_write, + .device = uart_console_device, + .setup = ubi32_mailbox_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &ubi32_mailbox_reg, +}; + +static int __init ubi32_mailbox_console_init(void) +{ + ubi32_mailbox_init_ports(); + register_console(&ubi32_mailbox_console); + return 0; +} +console_initcall(ubi32_mailbox_console_init); + +#define UBI32_MAILBOX_CONSOLE &ubi32_mailbox_console +#else +#define UBI32_MAILBOX_CONSOLE NULL +#endif /* CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE */ + + +#ifdef CONFIG_EARLY_PRINTK +static __init void ubi32_mailbox_early_putc(struct uart_port *port, int ch) +{ + UART_PUT_CHAR(uart, ch); +} + +static __init void ubi32_mailbox_early_write(struct console *con, const char *s, + unsigned int n) +{ + struct ubi32_mailbox_port *uart = &ubi32_mailbox_ports[con->index]; + unsigned int i; + + for (i = 0; i < n; i++, s++) { + if (*s == '\n') + ubi32_mailbox_early_putc(&uart->port, '\r'); + ubi32_mailbox_early_putc(&uart->port, *s); + } +} + +static struct __init console ubi32_mailbox_early_console = { + .name = "early_UM", + .write = ubi32_mailbox_early_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .setup = ubi32_mailbox_console_setup, + .index = -1, + .data = &ubi32_mailbox_reg, +}; + +/* + * XXX Unused in our driver. Need to find out what the termios initialization is good/needed for. + */ +struct console __init *ubi32_mailbox_early_init(unsigned int port, + unsigned int cflag) +{ + struct ubi32_mailbox_port *uart; + struct ktermios t; + + if (port == -1 || port >= NR_PORTS) + port = 0; + ubi32_mailbox_init_ports(); + ubi32_mailbox_early_console.index = port; + uart = &ubi32_mailbox_ports[port]; + t.c_cflag = cflag; + t.c_iflag = 0; + t.c_oflag = 0; + t.c_lflag = ICANON; + t.c_line = port; + ubi32_mailbox_set_termios(&uart->port, &t, &t); + return &ubi32_mailbox_early_console; +} + +#endif /* CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE */ + +static struct uart_driver ubi32_mailbox_reg = { + .owner = THIS_MODULE, + .driver_name = "ubi32_mailbox", + .dev_name = UBI32_MAILBOX_NAME, + .major = UBI32_MAILBOX_MAJOR, + .minor = UBI32_MAILBOX_MINOR, + .nr = NR_PORTS, + .cons = UBI32_MAILBOX_CONSOLE, +}; + +static int ubi32_mailbox_suspend(struct platform_device *dev, pm_message_t state) +{ + struct ubi32_mailbox_port *uart = platform_get_drvdata(dev); + + if (uart) + uart_suspend_port(&ubi32_mailbox_reg, &uart->port); + + return 0; +} + +static int ubi32_mailbox_resume(struct platform_device *dev) +{ + struct ubi32_mailbox_port *uart = platform_get_drvdata(dev); + + if (uart) + uart_resume_port(&ubi32_mailbox_reg, &uart->port); + + return 0; +} + +static int ubi32_mailbox_probe(struct platform_device *dev) +{ + struct resource *res = dev->resource; + int i; + + for (i = 0; i < dev->num_resources; i++, res++) + if (res->flags & IORESOURCE_MEM) + break; + + if (i < dev->num_resources) { + for (i = 0; i < NR_PORTS; i++, res++) { + if (ubi32_mailbox_ports[i].port.mapbase != res->start) + continue; + ubi32_mailbox_ports[i].port.dev = &dev->dev; + uart_add_one_port(&ubi32_mailbox_reg, &ubi32_mailbox_ports[i].port); + platform_set_drvdata(dev, &ubi32_mailbox_ports[i]); + } + } + + return 0; +} + +static int ubi32_mailbox_remove(struct platform_device *pdev) +{ + struct ubi32_mailbox_port *uart = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (uart) + uart_remove_one_port(&ubi32_mailbox_reg, &uart->port); + + return 0; +} + +static struct platform_driver ubi32_mailbox_driver = { + .probe = ubi32_mailbox_probe, + .remove = ubi32_mailbox_remove, + .suspend = ubi32_mailbox_suspend, + .resume = ubi32_mailbox_resume, + .driver = { + .name = "ubi32-mbox", + .owner = THIS_MODULE, + }, +}; + +static int __init ubi32_mailbox_init(void) +{ + int ret; + + pr_info("Serial: Ubicom32 mailbox serial driver.\n"); + + mailbox_console_flg = TRUE; + num_timeouts = 0; + ubi32_mailbox_init_ports(); + + ret = uart_register_driver(&ubi32_mailbox_reg); + if (ret == 0) { + ret = platform_driver_register(&ubi32_mailbox_driver); + if (ret) { + pr_debug("uart register failed\n"); + uart_unregister_driver(&ubi32_mailbox_reg); + } + } + + /* + * XXX HACK: currently probe does not get called, but the port needs to be added to work. + */ + uart_add_one_port(&ubi32_mailbox_reg, &ubi32_mailbox_ports[0].port); + return ret; +} + +static void __exit ubi32_mailbox_exit(void) +{ + platform_driver_unregister(&ubi32_mailbox_driver); + uart_unregister_driver(&ubi32_mailbox_reg); +} + +module_init(ubi32_mailbox_init); +module_exit(ubi32_mailbox_exit); + +MODULE_ALIAS_CHARDEV_MAJOR(UBI32_MAILBOX_MAJOR); +MODULE_ALIAS("platform:ubi32_mailbox"); diff --git a/target/linux/ubicom32/files/drivers/serial/ubi32_serdes.c b/target/linux/ubicom32/files/drivers/serial/ubi32_serdes.c new file mode 100644 index 000000000..79037da49 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/serial/ubi32_serdes.c @@ -0,0 +1,817 @@ +/* + * drivers/serial/ubi32_serdes.c + * Ubicom32 On-Chip Serial Driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define SERIAL_UBICOM_PIN_RXD (1 << 0) +#define SERIAL_UBICOM_PIN_TXD (1 << 6) +#define SERIAL_UBICOM_CTL0 0x8b300000 +#define SERIAL_UBICOM_CTL1 0x00000009 + +#define SERIAL_UBICOM_DATA_BIT 8 /* Fixed parameter - do not change */ +#define SERIAL_UBICOM_PAR_BIT 0 /* Fixed parameter - do not change */ +#define SERIAL_UBICOM_STOP_BIT 1 /* Fixed parameter - do not change */ + +/* UART name and device definitions */ +#define UBI32_SERDES_NAME "ttyUS" // XXX +#define UBI32_SERDES_MAJOR 206 // XXX +#define UBI32_SERDES_MINOR 64 // XXX + +#define PORT_UBI32_SERDES 1234 +#define NR_PORTS 1 + +struct uart_port ubi32_serdes_ports[NR_PORTS]; + +struct ubi32_serdes_resource { + void *uart_base_addr; + int uart_irq; + int uart_clock; +} ubi32_serdes_resource[NR_PORTS] = { + /* + * Get params from kernel command line (required for early printk) + * or from platform resources. + */ + {0, 0, 0} +}; + +/* + * Can get overridden by 'serdes=' kernel command line. + */ +static int ubi32_serdes_default_baud_rate = 115200; + + +#define IO_PORT(port) ((struct ubicom32_io_port *)port->membase) +#define IO_PORT_INT_STATUS(port) (IO_PORT(port)->int_status) +#define IO_PORT_INT_MASK(port) (IO_PORT(port)->int_mask) +#define IO_PORT_INT_CLR(port) (IO_PORT(port)->int_clr) + + +/* + * ubi32_serdes_get_char() + */ +static u8_t ubi32_serdes_get_char(struct ubicom32_io_port *io_port) +{ + /* + * Read from hardware (forced 32-bit atomic read). + */ + u32_t data = 0; + + if ( io_port ) { + io_port->int_clr = IO_PORTX_INT_SERDES_RXBF; + asm volatile ( + "move.4 %0, %1 \n\t" + : "=r" (data) + : "m" (*(u32_t *)&(io_port->rx_fifo)) + ); + } + + return (u8_t)(data & 0x000000ff); +} + +/* + * ubi32_serdes_put_char() + */ +static void ubi32_serdes_put_char(struct ubicom32_io_port *io_port, u8_t c) +{ + u32_t data = 0x0000fe00 | (c << 1); + + if ( io_port ) { + /* + * Fixed data format: + * [LSB]1 start bit - 8 data bits - no parity - 1 stop bit[MSB] + */ + io_port->int_clr = IO_PORTX_INT_SERDES_TXBE; + io_port->ctl2 = data; + io_port->int_set = IO_PORTX_INT_SERDES_TXBUF_VALID; + } +} + +static void ubi32_serdes_hw_init(struct uart_port *port, int baud) +{ + struct ubicom32_io_port *io_port = IO_PORT(port); + + if ( io_port ) { + /* + * Put port functions 1-4 into reset state. + * Function 0 (GPIO) does not need or have a reset bit. + * + * Select SERDES function for restart below. + */ + io_port->function = + IO_FUNC_FUNCTION_RESET(1) | IO_FUNC_FUNCTION_RESET(2) | + IO_FUNC_FUNCTION_RESET(3) | IO_FUNC_FUNCTION_RESET(4) | + IO_PORTX_FUNC_SERDES; + + /* + * Configure SERDES baudrate + */ + if ( baud == 0 ) { + baud = ubi32_serdes_default_baud_rate; + } + + io_port->ctl0 = + SERIAL_UBICOM_CTL0 | + ((port->uartclk / (16 * baud)) - 1); + + io_port->ctl1 = + SERIAL_UBICOM_CTL1; + + /* + * don't interrupt until startup and start_tx + */ + io_port->int_mask = 0; + + /* + * Set TXD pin output, RXD input and prevent GPIO + * override on the TXD & RXD pins + */ + io_port->gpio_ctl &= ~SERIAL_UBICOM_PIN_RXD; + io_port->gpio_ctl |= SERIAL_UBICOM_PIN_TXD; + io_port->gpio_mask &= ~(SERIAL_UBICOM_PIN_RXD | SERIAL_UBICOM_PIN_TXD); + + /* + * Restart (un-reset) the port's SERDES function. + */ + io_port->function &= ~(IO_FUNC_FUNCTION_RESET(IO_PORTX_FUNC_SERDES)); + } +} + +#define ULITE_STATUS_RXVALID IO_PORTX_INT_SERDES_RXBF +#define ULITE_STATUS_OVERRUN 0 +#define ULITE_STATUS_FRAME 0 +#define ULITE_STATUS_PARITY 0 +#define ULITE_STATUS_TXEMPTY IO_PORTX_INT_SERDES_TXBE +#define ULITE_STATUS_TXFULL 0 + +static int ubi32_serdes_receive(struct uart_port *port, int stat) +{ + struct tty_struct *tty = port->info->port.tty; + unsigned char ch = 0; + char flag = TTY_NORMAL; + + if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN + | ULITE_STATUS_FRAME)) == 0) + return 0; + + /* stats */ + if (stat & ULITE_STATUS_RXVALID) { + port->icount.rx++; + ch = ubi32_serdes_get_char((struct ubicom32_io_port *)port->membase); + + if (stat & ULITE_STATUS_PARITY) + port->icount.parity++; + } + + if (stat & ULITE_STATUS_OVERRUN) + port->icount.overrun++; + + if (stat & ULITE_STATUS_FRAME) + port->icount.frame++; + + + /* drop byte with parity error if IGNPAR specificed */ + if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY) + stat &= ~ULITE_STATUS_RXVALID; + + stat &= port->read_status_mask; + + if (stat & ULITE_STATUS_PARITY) + flag = TTY_PARITY; + + stat &= ~port->ignore_status_mask; + + if (stat & ULITE_STATUS_RXVALID) + tty_insert_flip_char(tty, ch, flag); + + if (stat & ULITE_STATUS_FRAME) + tty_insert_flip_char(tty, 0, TTY_FRAME); + + if (stat & ULITE_STATUS_OVERRUN) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + return 1; +} + +/* + * interrupts are disabled on entry + */ +static void ubi32_serdes_stop_tx(struct uart_port *port) +{ + IO_PORT_INT_MASK(port) = IO_PORT_INT_MASK(port) & ~IO_PORTX_INT_SERDES_TXBE; +} + +static int ubi32_serdes_transmit(struct uart_port *port, int stat) +{ + struct circ_buf *xmit = &port->info->xmit; + + if (!(stat & IO_PORTX_INT_SERDES_TXBE)) + return 0; + + if (port->x_char) { + ubi32_serdes_put_char(IO_PORT(port), port->x_char); + port->x_char = 0; + port->icount.tx++; + return 1; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + ubi32_serdes_stop_tx(port); + return 0; + } + + ubi32_serdes_put_char(IO_PORT(port), xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); + port->icount.tx++; + + /* wake up */ + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + ubi32_serdes_stop_tx(port); + + return 1; +} + +/* + * port is locked and interrupts are disabled + */ +static void ubi32_serdes_start_tx(struct uart_port *port) +{ + IO_PORT_INT_MASK(port) = IO_PORT_INT_MASK(port) | IO_PORTX_INT_SERDES_TXBE; + ubi32_serdes_transmit(port, IO_PORT_INT_STATUS(port)); +} + +/* + * Interrupts are enabled + */ +static void ubi32_serdes_stop_rx(struct uart_port *port) +{ + /* don't forward any more data (like !CREAD) */ + port->ignore_status_mask = IO_PORTX_INT_SERDES_RXBF; +} + +/* + * Set the modem control timer to fire immediately. + */ +static void ubi32_serdes_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +static irqreturn_t ubi32_serdes_isr(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + int busy; + + spin_lock(&port->lock); + + do { + int stat = IO_PORT_INT_STATUS(port); + busy = ubi32_serdes_receive(port, stat); + busy |= ubi32_serdes_transmit(port, stat); + } while (busy); + + tty_flip_buffer_push(port->info->port.tty); + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int ubi32_serdes_tx_empty(struct uart_port *port) +{ + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + ret = IO_PORT_INT_STATUS(port); + spin_unlock_irqrestore(&port->lock, flags); + + return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; +} + +static unsigned int ubi32_serdes_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void ubi32_serdes_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* N/A */ +} + +/* + * Interrupts are always disabled. + */ +static void ubi32_serdes_break_ctl(struct uart_port *port, int break_state) +{ + /* N/A */ +} + +static int ubi32_serdes_startup(struct uart_port *port) +{ + if (request_irq(port->irq, ubi32_serdes_isr, IRQF_DISABLED, + "UBI32_SERDES", port)) { + printk(KERN_NOTICE "Unable to attach port interrupt\n"); + return -EBUSY; + } + + IO_PORT_INT_CLR(port) = IO_PORTX_INT_SERDES_RXBF; + IO_PORT_INT_MASK(port) = IO_PORTX_INT_SERDES_RXBF; + return 0; +} + +static void ubi32_serdes_shutdown(struct uart_port *port) +{ + struct ubi32_serdes_port *uart = (struct ubi32_serdes_port *)port; + + IO_PORT_INT_MASK(port) = 0; + free_irq(port->irq, uart); +} + +static void +ubi32_serdes_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud; + + spin_lock_irqsave(&port->lock, flags); + + port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN + | ULITE_STATUS_TXFULL; + + if (termios->c_iflag & INPCK) + port->read_status_mask |= + ULITE_STATUS_PARITY | ULITE_STATUS_FRAME; + + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= ULITE_STATUS_PARITY + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; + + /* ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= + ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; + + /* update timeout */ + baud = uart_get_baud_rate(port, termios, old, 0, 460800); + uart_update_timeout(port, termios->c_cflag, baud); + + IO_PORT(port)->ctl0 = SERIAL_UBICOM_CTL0 | + ((port->uartclk / (16 * baud)) - 1); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *ubi32_serdes_type(struct uart_port *port) +{ + return port->type == PORT_UBI32_SERDES ? "UBI32_SERDES" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void ubi32_serdes_release_port(struct uart_port *port) +{ +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int ubi32_serdes_request_port(struct uart_port *port) +{ + return 0; +} + +/* + * Configure/autoconfigure the port. + */ +static void ubi32_serdes_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE && + ubi32_serdes_request_port(port) == 0) + port->type = PORT_UBI32_SERDES; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + * The only change we allow are to the flags and type, and + * even then only between PORT_UBI32_SERDES and PORT_UNKNOWN + */ +static int +ubi32_serdes_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return 0; +} + +static struct uart_ops ubi32_serdes_pops = { + .tx_empty = ubi32_serdes_tx_empty, + .set_mctrl = ubi32_serdes_set_mctrl, + .get_mctrl = ubi32_serdes_get_mctrl, + .stop_tx = ubi32_serdes_stop_tx, + .start_tx = ubi32_serdes_start_tx, + .stop_rx = ubi32_serdes_stop_rx, + .enable_ms = ubi32_serdes_enable_ms, + .break_ctl = ubi32_serdes_break_ctl, + .startup = ubi32_serdes_startup, + .shutdown = ubi32_serdes_shutdown, + .set_termios = ubi32_serdes_set_termios, + .type = ubi32_serdes_type, + .release_port = ubi32_serdes_release_port, + .request_port = ubi32_serdes_request_port, + .config_port = ubi32_serdes_config_port, + .verify_port = ubi32_serdes_verify_port, +}; + +static void __init ubi32_serdes_init_ports(void) +{ + int i; + + for (i = 0; i < NR_PORTS; i++) { + ubi32_serdes_ports[i].uartclk = ubi32_serdes_resource[i].uart_clock; + ubi32_serdes_ports[i].ops = &ubi32_serdes_pops; + ubi32_serdes_ports[i].line = i; + ubi32_serdes_ports[i].iotype = UPIO_MEM; + ubi32_serdes_ports[i].membase = + (void __iomem *)ubi32_serdes_resource[i].uart_base_addr; + ubi32_serdes_ports[i].mapbase = + (resource_size_t)ubi32_serdes_resource[i].uart_base_addr; + ubi32_serdes_ports[i].irq = + ubi32_serdes_resource[i].uart_irq; + ubi32_serdes_ports[i].flags = UPF_BOOT_AUTOCONF; + + ubi32_serdes_hw_init(&ubi32_serdes_ports[i], 0); + } + +} + +#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE +/* + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init +ubi32_serdes_console_get_options(struct uart_port *port, int *baud) +{ + u32 round_to = 1200; + u32 real_baud; + + /* + * We might get called before platform init and with no + * kernel command line options, so port might be NULL. + */ + *baud = ubi32_serdes_default_baud_rate;; + if ( IO_PORT(port) == 0 ) + return; + + real_baud = port->uartclk + / (16 * ((IO_PORT(port)->ctl0 & ~SERIAL_UBICOM_CTL0) + 1)); + + *baud = ((real_baud + round_to - 1) / round_to) * round_to; + + pr_debug("%s:baud = %d, real_baud = %d\n", __FUNCTION__, *baud, real_baud); +} +#endif + +#if defined(CONFIG_SERIAL_UBI32_SERDES_CONSOLE) || defined(CONFIG_EARLY_PRINTK) +static struct uart_driver ubi32_serdes_reg; + +static int __init +ubi32_serdes_console_setup(struct console *co, char *options) +{ + struct uart_port *port; +#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE + int baud = ubi32_serdes_default_baud_rate; + int bits = 8; + int parity = 'n'; + int flow = 'n'; +#endif + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= NR_PORTS) + co->index = 0; + port = &ubi32_serdes_ports[co->index]; + +#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE + if (options) { + uart_parse_options(options, &baud, &parity, &bits, &flow); + ubi32_serdes_hw_init(port, baud); + } + else + ubi32_serdes_console_get_options(port, &baud); + + return uart_set_options(port, co, baud, parity, bits, flow); +#else + return 0; +#endif +} +#endif /* defined (CONFIG_SERIAL_UBI32_SERDES_CONSOLE) || + defined (CONFIG_EARLY_PRINTK) */ + +#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE +static void +ubi32_serdes_console_putchar(struct uart_port *port, int ch) +{ + if ( IO_PORT(port) ) { + while (!(IO_PORT_INT_STATUS(port) & IO_PORTX_INT_SERDES_TXBE)) + barrier(); + ubi32_serdes_put_char(IO_PORT(port), ch); + } +} + +/* + * Interrupts are disabled on entering + */ +static void +ubi32_serdes_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &ubi32_serdes_ports[co->index]; + unsigned long flags = 0; + + spin_lock_irqsave(&port->lock, flags); + uart_console_write(port, s, count, ubi32_serdes_console_putchar); + spin_unlock_irqrestore(&port->lock, flags); + +} + +static struct console ubi32_serdes_console = { + .name = UBI32_SERDES_NAME, + .write = ubi32_serdes_console_write, + .device = uart_console_device, + .setup = ubi32_serdes_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &ubi32_serdes_reg, +}; + +static int __init ubi32_serdes_console_init(void) +{ + ubi32_serdes_init_ports(); + register_console(&ubi32_serdes_console); + return 0; +} +console_initcall(ubi32_serdes_console_init); + +#define UBI32_SERDES_CONSOLE &ubi32_serdes_console +#else +#define UBI32_SERDES_CONSOLE NULL +#endif /* CONFIG_SERIAL_UBI32_SERDES_CONSOLE */ + + +#ifdef CONFIG_EARLY_PRINTK +static __init void ubi32_serdes_early_putc(struct uart_port *port, int ch) +{ + unsigned timeout = 0xffff; + + while ((!(IO_PORT_INT_STATUS(port) & IO_PORTX_INT_SERDES_TXBE)) && --timeout) + cpu_relax(); + ubi32_serdes_put_char(IO_PORT(port), ch); +} + +static __init void ubi32_serdes_early_write(struct console *con, const char *s, + unsigned int n) +{ + struct uart_port *port = &ubi32_serdes_ports[con->index]; + unsigned int i; + + for (i = 0; i < n; i++, s++) { + if (*s == '\n') + ubi32_serdes_early_putc(port, '\r'); + ubi32_serdes_early_putc(port, *s); + } +} + +static struct __init console ubi32_serdes_early_console = { + .name = "early_US", + .write = ubi32_serdes_early_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .setup = ubi32_serdes_console_setup, + .index = -1, + .data = &ubi32_serdes_reg, +}; + +/* + * XXX Unused in our driver. Need to find out what the termios initialization is good/needed for. + */ +struct console __init *ubi32_serdes_early_init(unsigned int port_index, + unsigned int cflag) +{ + struct uart_port *uart; + struct ktermios t; + + if (port_index == -1 || port_index >= NR_PORTS) + port_index = 0; + ubi32_serdes_init_ports(); + ubi32_serdes_early_console.index = port_index; + uart = &ubi32_serdes_ports[port_index]; + t.c_cflag = cflag; + t.c_iflag = 0; + t.c_oflag = 0; + t.c_lflag = ICANON; + t.c_line = port_index; + ubi32_serdes_set_termios(uart, &t, &t); + return &ubi32_serdes_early_console; +} + +#endif /* CONFIG_SERIAL_UBI32_SERDES_CONSOLE */ + +static struct uart_driver ubi32_serdes_reg = { + .owner = THIS_MODULE, + .driver_name = "ubi32_serdes", + .dev_name = UBI32_SERDES_NAME, + .major = UBI32_SERDES_MAJOR, + .minor = UBI32_SERDES_MINOR, + .nr = NR_PORTS, + .cons = UBI32_SERDES_CONSOLE, +}; + +static int ubi32_serdes_suspend(struct platform_device *dev, pm_message_t state) +{ + struct uart_port *port = platform_get_drvdata(dev); + + if (port) + uart_suspend_port(&ubi32_serdes_reg, port); + + return 0; +} + +static int ubi32_serdes_resume(struct platform_device *dev) +{ + struct uart_port *port = platform_get_drvdata(dev); + + if (port) + uart_resume_port(&ubi32_serdes_reg, port); + + return 0; +} + +static int ubi32_serdes_probe(struct platform_device *dev) +{ + struct resource *res = dev->resource; + int i; + + for (i = 0; i < dev->num_resources; i++, res++) { + if (res->flags & IORESOURCE_MEM) { + ubi32_serdes_resource[0].uart_base_addr = (void *) res->start; + } + else if (res->flags & IORESOURCE_IRQ) { + ubi32_serdes_resource[0].uart_irq = res->start; + } + else if (res->flags & UBICOM32_SUART_IORESOURCE_CLOCK) { + ubi32_serdes_resource[0].uart_clock = res->start; + } + } + + ubi32_serdes_init_ports(); + + return 0; +} + +static int ubi32_serdes_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (port) + uart_remove_one_port(&ubi32_serdes_reg, port); + + return 0; +} + +static struct platform_driver ubi32_serdes_driver = { + .remove = ubi32_serdes_remove, + .suspend = ubi32_serdes_suspend, + .resume = ubi32_serdes_resume, + .driver = { + .name = "ubicom32suart", + .owner = THIS_MODULE, + }, +}; + + +#ifndef MODULE +/* + * Called at boot time. + * + * You can specify IO base, IRQ, and clock for the serdes serial port + * using kernel command line "serdes=0xiobase,irq,clock". Values + * specified will be overwritten by platform device data, if present. + */ +static int __init ubi32_serdes_setup(char *str) +{ +#define N_PARMS (4+1) + int ints[N_PARMS]; + int i; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + for (i = 0; i < N_PARMS; i++) { + if (i < ints[0]) { + if (i == 0) { + ubi32_serdes_resource[0].uart_base_addr = (void *) ints[i+1]; + } + else if (i == 1) { + ubi32_serdes_resource[0].uart_irq = ints[i+1]; + } + else if (i == 2) { + ubi32_serdes_resource[0].uart_clock = ints[i+1]; + } + else if (i == 3) { + ubi32_serdes_default_baud_rate = ints[i+1]; + } + } + } + return 1; +} + +__setup("serdes=", ubi32_serdes_setup); +#endif + +static int __init ubi32_serdes_init(void) +{ + int ret; + + pr_info("Serial: Ubicom32 serdes uart serial driver\n"); + + ret = platform_driver_probe(&ubi32_serdes_driver, ubi32_serdes_probe); + if (ret != 0) { + printk(KERN_INFO "serdes platform_driver_probe() failed: %d\n", ret); + return ret; + } + + ubi32_serdes_init_ports(); + + ret = uart_register_driver(&ubi32_serdes_reg); + if ( ret == 0 ) { + ret = uart_add_one_port(&ubi32_serdes_reg, &ubi32_serdes_ports[0]); + if ( ret != 0 ) { + uart_unregister_driver(&ubi32_serdes_reg); + } + } + + return ret; +} + +static void __exit ubi32_serdes_exit(void) +{ + platform_driver_unregister(&ubi32_serdes_driver); + uart_unregister_driver(&ubi32_serdes_reg); +} + +module_init(ubi32_serdes_init); +module_exit(ubi32_serdes_exit); + +MODULE_AUTHOR("Rainer Keller "); +MODULE_DESCRIPTION("Ubicom generic serial port driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(UBI32_SERDES_MAJOR); +MODULE_ALIAS("platform:ubi32_serdes"); diff --git a/target/linux/ubicom32/files/drivers/serial/ubi32_uarttio.c b/target/linux/ubicom32/files/drivers/serial/ubi32_uarttio.c new file mode 100644 index 000000000..7aa374200 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/serial/ubi32_uarttio.c @@ -0,0 +1,1172 @@ +/* + * drivers/serial/ubi32_uarttio.c + * Ubicom32 Serial Virtual Peripherial Driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DRIVER_NAME "ubi32_uarttio" + +/* + * For storing the module parameters. + */ +#define UBI32_UARTTIO_MAX_PARAM_LEN 80 +static char utio_ports_param[UBI32_UARTTIO_MAX_PARAM_LEN]; + +/* + * UART name and device definitions + */ +#define UBI32_UARTTIO_NAME "ttyUV" // XXX +#define UBI32_UARTTIO_MAJOR 206 // XXX +#define UBI32_UARTTIO_MINOR 64 // XXX + +/* + * The following structures are allocated statically because the + * memory allocation subsystem is not initialized this early on + */ + +/* + * Per port structure + */ +struct ubi32_uarttio_port { + struct uarttio_uart *uart; + unsigned int tx_pin; + unsigned int rx_pin; + + struct uart_port port; + + u8_t added; + + /* + * If this value is set, the port has had its direction set already + */ + u8_t port_init; +}; +static struct ubi32_uarttio_port uarttio_ports[CONFIG_SERIAL_UBI32_UARTTIO_NR_UARTS]; + +/* + * Number of ports currently initialized + */ +static int uarttio_nports; + +/* + * Per device structure + */ +struct ubi32_uarttio_instance { + struct uarttio_regs *regs; + struct ubi32_uarttio_port *ports; + + u8_t irq_requested; + u8_t driver_registered; + u8_t irq; +}; +static struct ubi32_uarttio_instance uarttio_inst; + +#ifdef CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE +static struct console ubi32_uarttio_console; +#define UBI32_UARTTIO_CONSOLE &ubi32_uarttio_console +#else +#define UBI32_UARTTIO_CONSOLE NULL +#endif + +static struct uart_driver ubi32_uarttio_uart_driver = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = UBI32_UARTTIO_NAME, + .major = UBI32_UARTTIO_MAJOR, + .minor = UBI32_UARTTIO_MINOR, + .cons = UBI32_UARTTIO_CONSOLE, +}; + +#ifdef UBI32_UARTTIO_UNUSED +/* + * ubi32_uarttio_get_send_space + */ +static int ubi32_uarttio_get_send_space(struct uarttio_uart *uart) +{ + int count = uart->tx_fifo_head - uart->tx_fifo_tail; + if (count < 0) { + count += uart->tx_fifo_size; + } + return uart->tx_fifo_size - count; +} +#endif + +/* + * ubi32_uarttio_get_recv_ready + */ +static int ubi32_uarttio_get_recv_ready(struct uarttio_uart *uart) +{ + int count = uart->rx_fifo_head - uart->rx_fifo_tail; + if (count < 0) { + count += uart->rx_fifo_size; + } + return count; +} + +/* + * ubi32_uarttio_get_char() + */ +static u8_t ubi32_uarttio_get_char(struct uarttio_uart *uart) +{ + /* + * Retrieve byte + */ + u32_t tail = uart->rx_fifo_tail; + u8_t data = uart->rx_fifo[tail]; + + if (++tail == uart->rx_fifo_size) { + tail = 0; + } + uart->rx_fifo_tail = tail; + + return data; +} + +/* + * ubi32_uarttio_put_char() + */ +static int ubi32_uarttio_put_char(struct uarttio_uart *uart, u8_t c) +{ + u32_t head = uart->tx_fifo_head; + u32_t prev = head; + + /* + * Wrap + */ + if (++head == uart->tx_fifo_size) { + head = 0; + } + + /* + * If there isn't any space, return EBUSY + */ + if (head == uart->tx_fifo_tail) { + return -EBUSY; + } + + /* + * Put the character in the queue + */ + uart->tx_fifo[prev] = c; + uart->tx_fifo_head = head; + + return 0; +} + +/* + * ubi32_uarttio_set_baud + */ +static int ubi32_uarttio_set_baud(struct ubi32_uarttio_port *uup, unsigned int baud) +{ + if (uup->uart->current_baud_rate == baud) { + return 0; + } + + uup->uart->baud_rate = baud; + uup->uart->flags |= UARTTIO_UART_FLAG_SET_RATE; + while (uup->uart->flags & UARTTIO_UART_FLAG_SET_RATE) { + cpu_relax(); + } + + if (uup->uart->current_baud_rate != baud) { + /* + * Failed to set baud rate + */ + printk(KERN_WARNING "Invalid baud rate %u, running at %u\n", baud, uup->uart->current_baud_rate); + return -EINVAL; + } + + return 0; +} + +/* + * ubi32_uarttio_handle_receive + */ +static void ubi32_uarttio_handle_receive(struct ubi32_uarttio_port *uup, int stat) +{ + struct uarttio_uart *uart = uup->uart; + struct uart_port *port = &uup->port; + struct tty_struct *tty = port->info->port.tty; + unsigned char ch = 0; + char flag = TTY_NORMAL; + int count; + + if ((stat & (UARTTIO_UART_INT_RX | UARTTIO_UART_INT_RXFRAME | UARTTIO_UART_INT_RXOVF)) == 0) { + return; + } + + if (stat & UARTTIO_UART_INT_RX) { + count = ubi32_uarttio_get_recv_ready(uart); + port->icount.rx += count; + } + + if (stat & UARTTIO_UART_INT_RXOVF) { + port->icount.overrun++; + } + + if (stat & UARTTIO_UART_INT_RXFRAME) { + port->icount.frame++; + } + + stat &= ~port->ignore_status_mask; + + if (stat & UARTTIO_UART_INT_RX) { + int i; + for (i = 0; i < count; i++) { + ch = ubi32_uarttio_get_char(uart); + tty_insert_flip_char(tty, ch, flag); + } + } + + if (stat & UARTTIO_UART_INT_RXFRAME) { + tty_insert_flip_char(tty, 0, TTY_FRAME); + } + + if (stat & UARTTIO_UART_INT_RXOVF) { + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } +} + +/* + * ubi32_uarttio_stop_tx + * interrupts are disabled on entry + */ +static void ubi32_uarttio_stop_tx(struct uart_port *port) +{ + struct ubi32_uarttio_port *uup = port->private_data; + + uup->uart->int_mask &= ~UARTTIO_UART_INT_TXBE; +} + +/* + * ubi32_uarttio_handle_transmit + */ +static void ubi32_uarttio_handle_transmit(struct ubi32_uarttio_port *uup, int stat) +{ + struct uarttio_uart *uart = uup->uart; + struct uart_port *port = &uup->port; + struct circ_buf *xmit = &port->info->xmit; + + if (!(stat & UARTTIO_UART_INT_TXBE)) { + return; + } + + if (port->x_char) { + if (ubi32_uarttio_put_char(uart, port->x_char)) { + return; + } + port->x_char = 0; + port->icount.tx++; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + ubi32_uarttio_stop_tx(port); + return; + } + + /* + * Send as many characters as we can + */ + while (ubi32_uarttio_put_char(uart, xmit->buf[xmit->tail]) == 0) { + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) { + break; + } + } + + /* wake up */ + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { + uart_write_wakeup(port); + } + + if (uart_circ_empty(xmit)) { + ubi32_uarttio_stop_tx(port); + } +} + +/* + * ubi32_uarttio_start_tx + * port is locked and interrupts are disabled + */ +static void ubi32_uarttio_start_tx(struct uart_port *port) +{ + struct ubi32_uarttio_port *uup = port->private_data; + struct uarttio_uart *uart = uup->uart; + + uart->int_mask |= UARTTIO_UART_INT_TXBE; +} + +/* + * ubi32_uarttio_stop_rx + * Interrupts are enabled + */ +static void ubi32_uarttio_stop_rx(struct uart_port *port) +{ + struct ubi32_uarttio_port *uup = port->private_data; + struct uarttio_uart *uart = uup->uart; + + /* + * don't forward any more data (like !CREAD) + */ + uart->int_mask &= ~UARTTIO_UART_INT_RX; + port->ignore_status_mask = UARTTIO_UART_INT_RX; +} + +/* + * ubi32_uarttio_enable_ms + * Set the modem control timer to fire immediately. + */ +static void ubi32_uarttio_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +/* + * ubi32_uarttio_isr + */ +static irqreturn_t ubi32_uarttio_isr(int irq, void *appdata) +{ + struct ubi32_uarttio_port *uup = uarttio_ports; + int i; + + /* + * Service all of the ports + */ + for (i = 0; i < uarttio_nports; i++) { + unsigned int flags; + + if (!(uup->uart->flags & UARTTIO_UART_FLAG_ENABLED)) { + uup++; + continue; + } + + spin_lock(&uup->port.lock); + + flags = uup->uart->int_flags; + + uup->uart->int_flags = 0; + + ubi32_uarttio_handle_receive(uup, flags); + ubi32_uarttio_handle_transmit(uup, flags); + + tty_flip_buffer_push(uup->port.info->port.tty); + + spin_unlock(&uup->port.lock); + + uup++; + } + + return IRQ_HANDLED; +} + +/* + * ubi32_uarttio_tx_empty + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int ubi32_uarttio_tx_empty(struct uart_port *port) +{ + struct ubi32_uarttio_port *uup = port->private_data; + + if (uup->uart->tx_fifo_head == uup->uart->tx_fifo_tail) { + return TIOCSER_TEMT; + } + + return 0; +} + +/* + * ubi32_uarttio_get_mctrl + */ +static unsigned int ubi32_uarttio_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +/* + * ubi32_uarttio_set_mctrl + */ +static void ubi32_uarttio_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* N/A */ +} + +/* + * ubi32_uarttio_break_ctl + */ +static void ubi32_uarttio_break_ctl(struct uart_port *port, int break_state) +{ + /* N/A */ +} + +/* + * ubi32_uarttio_startup + */ +static int ubi32_uarttio_startup(struct uart_port *port) +{ + struct ubi32_uarttio_port *uup = port->private_data; + struct uarttio_uart *uart = uup->uart; + + uart->flags |= UARTTIO_UART_FLAG_ENABLED; + + uart->int_mask |= UARTTIO_UART_INT_TXBE | UARTTIO_UART_INT_RX; + + return 0; +} + +/* + * ubi32_uarttio_shutdown + */ +static void ubi32_uarttio_shutdown(struct uart_port *port) +{ + struct ubi32_uarttio_port *uup = port->private_data; + struct uarttio_uart *uart = uup->uart; + + uart->int_mask = 0; + uart->flags &= ~UARTTIO_UART_FLAG_ENABLED; +} + +/* + * ubi32_uarttio_set_termios + */ +static void ubi32_uarttio_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) +{ + struct ubi32_uarttio_port *uup = port->private_data; + unsigned long flags; + unsigned int baud; + + spin_lock_irqsave(&port->lock, flags); + +#if 0 + port->read_status_mask = UBI32_UARTTIO_RX | UBI32_UARTTIO_RXOVF | UBI32_UARTTIO_TXOVF; + + if (termios->c_iflag & INPCK) { + port->read_status_mask |= UBI32_UARTTIO_RXFRAME; + } +#endif + + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) { + port->ignore_status_mask |= UARTTIO_UART_INT_RXFRAME | + UARTTIO_UART_INT_RXOVF; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) { + port->ignore_status_mask |= UARTTIO_UART_INT_RX | + UARTTIO_UART_INT_RXFRAME | + UARTTIO_UART_INT_RXOVF; + } + + /* update timeout */ + baud = uart_get_baud_rate(port, termios, old, 0, 460800); + uart_update_timeout(port, termios->c_cflag, baud); + + ubi32_uarttio_set_baud(uup, baud); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* + * ubi32_uarttio_type + */ +static const char *ubi32_uarttio_type(struct uart_port *port) +{ + return (port->type == PORT_UBI32_UARTTIO) ? "UBI32_UARTTIO" : NULL; +} + +/* + * ubi32_uarttio_release_port + * Release the memory region(s) being used by 'port'. + */ +static void ubi32_uarttio_release_port(struct uart_port *port) +{ +} + +/* + * ubi32_uarttio_request_port + * Request the memory region(s) being used by 'port'. + */ +static int ubi32_uarttio_request_port(struct uart_port *port) +{ + return 0; +} + +/* + * ubi32_uarttio_config_port + * Configure/autoconfigure the port. + */ +static void ubi32_uarttio_config_port(struct uart_port *port, int flags) +{ + if ((flags & UART_CONFIG_TYPE) && (ubi32_uarttio_request_port(port) == 0)) { + port->type = PORT_UBI32_UARTTIO; + } +} + +/* + * ubi32_uarttio_verify_port + * Verify the new serial_struct (for TIOCSSERIAL). + * + * The only change we allow are to the flags and type, and + * even then only between PORT_UBI32_UARTTIO and PORT_UNKNOWN + */ +static int ubi32_uarttio_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return 0; +} + +static struct uart_ops ubi32_uarttio_pops = { + .tx_empty = ubi32_uarttio_tx_empty, + .set_mctrl = ubi32_uarttio_set_mctrl, + .get_mctrl = ubi32_uarttio_get_mctrl, + .stop_tx = ubi32_uarttio_stop_tx, + .start_tx = ubi32_uarttio_start_tx, + .stop_rx = ubi32_uarttio_stop_rx, + .enable_ms = ubi32_uarttio_enable_ms, + .break_ctl = ubi32_uarttio_break_ctl, + .startup = ubi32_uarttio_startup, + .shutdown = ubi32_uarttio_shutdown, + .set_termios = ubi32_uarttio_set_termios, + .type = ubi32_uarttio_type, + .release_port = ubi32_uarttio_release_port, + .request_port = ubi32_uarttio_request_port, + .config_port = ubi32_uarttio_config_port, + .verify_port = ubi32_uarttio_verify_port, +}; + +/* + * ubi32_uarttio_add_ports + */ +static int __init ubi32_uarttio_add_ports(void) +{ + int res = 0; + struct ubi32_uarttio_port *uup = uarttio_ports; + int i = 0; + + for (i = 0; i < uarttio_nports; i++) { + /* + * Setup the GPIOs + */ + res = gpio_request(uup->tx_pin, "ubi32_uarttio_tx"); + if (res) { + printk(KERN_WARNING "Failed to request GPIO %d\n", uup->tx_pin); + res = -EBUSY; + goto next; + } + + res = gpio_request(uup->rx_pin, "ubi32_uarttio_rx"); + if (res) { + gpio_free(uup->tx_pin); + printk(KERN_WARNING "Failed to request GPIO %d\n", uup->rx_pin); + res = -EBUSY; + goto next; + } + + res = uart_add_one_port(&ubi32_uarttio_uart_driver, &uup->port); + if (res) { + gpio_free(uup->rx_pin); + gpio_free(uup->tx_pin); + res = -ENODEV; + printk(KERN_WARNING "Failed to add port %d,%d\n", uup->tx_pin, uup->rx_pin); + goto next; + } + uup->added = 1; + + /* + * Set the direction of the ports now, after we're sure that everything is ok + */ + if (!uup->port_init) { + gpio_direction_output(uup->tx_pin, 1); + gpio_direction_input(uup->rx_pin); + } + +next: + uup++; + } + return res; +} + +/* + * ubi32_uarttio_cleanup + */ +static void ubi32_uarttio_cleanup(void) +{ + struct ubi32_uarttio_port *uup; + int i; + + /* + * Stop the hardware thread + */ + if (uarttio_inst.regs) { + thread_disable(uarttio_inst.regs->thread); + } + if (uarttio_inst.irq_requested) { + free_irq(uarttio_inst.irq, NULL); + } + + /* + * Get rid of the ports + */ + uup = uarttio_inst.ports; + for (i = 0; i < uarttio_nports; i++) { + gpio_free(uup->tx_pin); + gpio_free(uup->rx_pin); + if (uup->added) { + uart_remove_one_port(&ubi32_uarttio_uart_driver, &uup->port); + } + uup++; + } + + if (uarttio_inst.driver_registered) { + uart_unregister_driver(&ubi32_uarttio_uart_driver); + } +} + +/* + * ubi32_uarttio_setup_port + * Setup a port in the TIO registers + */ +static int ubi32_uarttio_setup_port(int index, + struct uarttio_uart *uart, + unsigned int baud, unsigned int tx_pin, + unsigned int rx_pin) +{ + struct ubi32_uarttio_port *uup = &uarttio_ports[index]; + void *tx_port = ubi_gpio_get_port(tx_pin); + void *rx_port = ubi_gpio_get_port(rx_pin); + + /* + * Verify the ports are on chip + */ + if (!tx_port || !rx_port) { + printk(KERN_WARNING "Invalid port(s) specified: %u or %u\n", tx_pin, rx_pin); + return -EINVAL; + } + + uup->tx_pin = tx_pin; + uup->rx_pin = rx_pin; + uup->uart = uart; + + /* + * Setup the port structure + */ + uup->port.ops = &ubi32_uarttio_pops; + uup->port.line = index; + uup->port.iotype = UPIO_MEM; + uup->port.flags = UPF_BOOT_AUTOCONF; + uup->port.fifosize = uup->uart->tx_fifo_size; + uup->port.private_data = uup; + + /* + * We share this IRQ across all ports + */ + uup->port.irq = uarttio_inst.irq; + + /* + * We really don't have a mem/map base but without these variables + * set, the serial_core won't startup. + */ + uup->port.membase = (void __iomem *)uup; + uup->port.mapbase = (resource_size_t)uup; + spin_lock_init(&uup->port.lock); + + /* + * Set up the hardware + */ + uart->flags = UARTTIO_UART_FLAG_SET_RATE | UARTTIO_UART_FLAG_RESET; + + uart->tx_port = (unsigned int)tx_port; + uart->tx_pin = gpio_pin_index(tx_pin); + uart->tx_bits = 8; + uart->tx_stop_bits = 1; + + uart->rx_port = (unsigned int)rx_port; + uart->rx_pin = gpio_pin_index(rx_pin); + uart->rx_bits = 8; + uart->rx_stop_bits = 1; + + uart->baud_rate = baud; + + return 0; +} + +enum ubi32_uarttio_parse_states { + UBI32_UARTTIO_PARSE_STATE_BAUD, + UBI32_UARTTIO_PARSE_STATE_TX_PIN, + UBI32_UARTTIO_PARSE_STATE_RX_PIN, + UBI32_UARTTIO_PARSE_STATE_HS, + UBI32_UARTTIO_PARSE_STATE_CTS_PIN, + UBI32_UARTTIO_PARSE_STATE_RTS_PIN, +}; + +/* + * ubi32_uarttio_parse_param + */ +static int ubi32_uarttio_parse_param(char *str) +{ + int res; + int i; + int baud = 0; + int tx_pin = 0; + int rx_pin = 0; + int hs = 0; + int cts_pin = 0; + int rts_pin = 0; + int nfound = 0; + enum ubi32_uarttio_parse_states state = UBI32_UARTTIO_PARSE_STATE_BAUD; + struct uarttio_uart *uart = uarttio_inst.regs->uarts; + + /* + * Run though the options and generate the proper structures + */ + res = get_option(&str, &i); + while ((res == 2) || (res == 1)) { + switch (state) { + case UBI32_UARTTIO_PARSE_STATE_BAUD: + /* + * If we are here and nfound > 0 then create the port + * based on the previous input + */ + if (nfound) { + /* + * Create the port + */ + if (ubi32_uarttio_setup_port(nfound - 1, uart, baud, tx_pin, rx_pin)) { + /* + * Port was invalid + */ + goto fail; + } else { + printk(KERN_INFO "Serial port %d: tx=%d:rx=%d @ %d\n", nfound, tx_pin, rx_pin, baud); + uart++; + } + } + + /* + * Reset the variables and go to the next state + */ + hs = 0; + baud = i; + state = UBI32_UARTTIO_PARSE_STATE_TX_PIN; + break; + + case UBI32_UARTTIO_PARSE_STATE_TX_PIN: + tx_pin = i; + state = UBI32_UARTTIO_PARSE_STATE_RX_PIN; + break; + + case UBI32_UARTTIO_PARSE_STATE_RX_PIN: + rx_pin = i; + state = UBI32_UARTTIO_PARSE_STATE_HS; + break; + + case UBI32_UARTTIO_PARSE_STATE_HS: + hs = i; + if (hs) { + state = UBI32_UARTTIO_PARSE_STATE_CTS_PIN; + break; + } + + if (nfound == uarttio_inst.regs->max_uarts) { + printk(KERN_WARNING "Maximum number of serial ports reached\n"); + goto done; + } + nfound++; + state = UBI32_UARTTIO_PARSE_STATE_BAUD; + break; + + case UBI32_UARTTIO_PARSE_STATE_CTS_PIN: + cts_pin = i; + state = UBI32_UARTTIO_PARSE_STATE_RTS_PIN; + break; + + case UBI32_UARTTIO_PARSE_STATE_RTS_PIN: + rts_pin = i; + + if (nfound == uarttio_inst.regs->max_uarts) { + printk(KERN_WARNING "Maximum number of serial ports reached\n"); + goto done; + } + nfound++; + state = UBI32_UARTTIO_PARSE_STATE_BAUD; + break; + } + res = get_option(&str, &i); + } + + if ((res > 2) || state != UBI32_UARTTIO_PARSE_STATE_BAUD) { + printk(KERN_WARNING "Parameter syntax error.\n"); + res = -EINVAL; + goto fail; + } + + /* + * Create the final port + */ + if (ubi32_uarttio_setup_port(nfound - 1, uart, baud, tx_pin, rx_pin)) { + goto fail; + } + printk(KERN_INFO "Serial port %d: tx=%d:rx=%d @ %d\n", nfound, tx_pin, rx_pin, baud); + +done: + uarttio_nports = nfound; + + return nfound ? 0 : -ENODEV; + +fail: + /* + * Reset the ports + */ + uart = uarttio_inst.regs->uarts; + for (i = 0; i < uarttio_inst.regs->max_uarts; i++) { + uart->flags = 0; + uart++; + } + + return res; +} + +/* + * ubi32_uarttio_probe + */ +static int ubi32_uarttio_probe(void) +{ + int ret; + struct uarttio_node *uart_node; + char *str = utio_ports_param; + static int probed; + static int probe_result; + + /* + * We only want to be probed once, we could be probed twice + * for example if we are used as a console + */ + if (probed) { + return probe_result; + } + probed = 1; + + /* + * Extract the TIO name from the setup string + */ + while (*str) { + if (*str == ',') { + *str++ = 0; + break; + } + str++; + } + + if (!*str) { + probe_result = -EINVAL; + return -EINVAL; + } + + uart_node = (struct uarttio_node *)devtree_find_node(utio_ports_param); + if (!uart_node) { + probe_result = -ENODEV; + return -ENODEV; + } + + uarttio_inst.irq = uart_node->dn.recvirq; + uarttio_inst.regs = uart_node->regs; + + /* + * Parse module parameters. + */ + ret = ubi32_uarttio_parse_param(str); + if (ret != 0) { + ubi32_uarttio_cleanup(); + probe_result = ret; + return ret; + } + + ubi32_uarttio_uart_driver.nr = uarttio_nports; + + return 0; +} + +#if defined(CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE) +/* + * ubi32_uarttio_console_setup + */ +static int __init ubi32_uarttio_console_setup(struct console *co, char *options) +{ + int baud; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + struct ubi32_uarttio_port *uup; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= uarttio_nports) { + co->index = 0; + } + uup = &uarttio_ports[co->index]; + baud = uup->uart->baud_rate; + uup->uart->flags |= UARTTIO_UART_FLAG_ENABLED; + + /* + * Setup the GPIOs + * We have to use the direct interface because the gpio + * subsystem is not available at this point. + */ + uup->port_init = 1; + UBICOM32_GPIO_SET_PIN_HIGH(uup->tx_pin); + UBICOM32_GPIO_SET_PIN_OUTPUT(uup->tx_pin); + UBICOM32_GPIO_SET_PIN_INPUT(uup->rx_pin); + + /* + * Start the thread + */ + thread_enable(uarttio_inst.regs->thread); + + /* + * Process options + */ + if (options) { + uart_parse_options(options, &baud, &parity, &bits, &flow); + if (ubi32_uarttio_set_baud(uup, baud)) { + baud = uup->uart->current_baud_rate; + } + } + + return uart_set_options(&uup->port, co, baud, 'n', 8, 'n'); +} + +/* + * ubi32_uarttio_console_putchar + */ +static void ubi32_uarttio_console_putchar(struct uart_port *port, int ch) +{ + struct ubi32_uarttio_port *uup = port->private_data; + + while (ubi32_uarttio_put_char(uup->uart, ch)) { + cpu_relax(); + } +} + +/* + * ubi32_uarttio_console_write + * Interrupts are disabled on entering + */ +static void ubi32_uarttio_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &(uarttio_ports[co->index].port); + unsigned long flags = 0; + + spin_lock_irqsave(&port->lock, flags); + uart_console_write(port, s, count, ubi32_uarttio_console_putchar); + spin_unlock_irqrestore(&port->lock, flags); +} + +static struct console ubi32_uarttio_console = { + .name = UBI32_UARTTIO_NAME, + .write = ubi32_uarttio_console_write, + .device = uart_console_device, + .setup = ubi32_uarttio_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &ubi32_uarttio_uart_driver, +}; + +static int __init ubi32_uarttio_console_init(void) +{ + int res; + + res = ubi32_uarttio_probe(); + if (res) { + return res; + } + + register_console(&ubi32_uarttio_console); + return 0; +} +console_initcall(ubi32_uarttio_console_init); +#endif /* CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE */ + +/* + * ubi32_serial_suspend + */ +static int ubi32_uarttio_suspend(struct platform_device *pdev, pm_message_t state) +{ + int i; + for (i = 0; i < uarttio_nports; i++) { + uart_suspend_port(&ubi32_uarttio_uart_driver, &uarttio_ports[i].port); + } + + return 0; +} + +/* + * ubi32_serial_resume + */ +static int ubi32_uarttio_resume(struct platform_device *pdev) +{ + int i; + for (i = 0; i < uarttio_nports; i++) { + uart_resume_port(&ubi32_uarttio_uart_driver, &uarttio_ports[i].port); + } + + return 0; +} + +/* + * ubi32_uarttio_remove + */ +static int __devexit ubi32_uarttio_remove(struct platform_device *pdev) +{ + ubi32_uarttio_cleanup(); + + uart_unregister_driver(&ubi32_uarttio_uart_driver); + + return 0; +} + +static struct platform_driver ubi32_uarttio_platform_driver = { + .remove = __devexit_p(ubi32_uarttio_remove), + .suspend = ubi32_uarttio_suspend, + .resume = ubi32_uarttio_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +#ifndef MODULE +/* + * Called at boot time. + * + * uarttio=TIONAME,(baud,tx_pin,rx_pin,handshake[,cts_pin,rts_pin],...) + * TIONAME is the name of the devtree node which describes the UARTTIO + * pin is the index of the pin, i.e. PA4 is 5 [(port * 32) + pin] + * handshake = 1 to enable handshaking, provide cts_pin, rts_pin (UNSUPPORTED) + * handshake = 0 to disable handshaking, do not provide cts_pin, rts_pin + * Ex: uarttio=UARTTIO,57600,7,6,0,9600,8,9,0 + */ +static int __init ubi32_uarttio_setup(char *str) +{ + strncpy(utio_ports_param, str, UBI32_UARTTIO_MAX_PARAM_LEN); + utio_ports_param[UBI32_UARTTIO_MAX_PARAM_LEN - 1] = 0; + return 1; +} +__setup("uarttio=", ubi32_uarttio_setup); +#endif + +/* + * ubi32_uarttio_init + */ +static int __init ubi32_uarttio_init(void) +{ + int ret; + int i; + + ret = ubi32_uarttio_probe(); + if (ret) { + return ret; + } + + /* + * Request the IRQ (do it here since many ports share the same IRQ) + */ + ret = request_irq(uarttio_inst.irq, ubi32_uarttio_isr, IRQF_DISABLED, DRIVER_NAME, NULL); + if (ret != 0) { + printk(KERN_WARNING "Could not request IRQ %d\n", uarttio_inst.irq); + goto fail; + } + uarttio_inst.irq_requested = 1; + + /* + * Register the UART driver and add the ports + */ + ret = uart_register_driver(&ubi32_uarttio_uart_driver); + if (ret != 0) { + goto fail; + } + uarttio_inst.driver_registered = 1; + + ret = ubi32_uarttio_add_ports(); + if (ret != 0) { + ubi32_uarttio_cleanup(); + return ret; + } + + /* + * Start the thread + */ + thread_enable(uarttio_inst.regs->thread); + + for (i = 0; i < uarttio_nports; i++) { + pr_info("Serial: Ubicom32 uarttio #%d: tx:%d rx:%d baud:%d\n", + i, uarttio_ports[i].tx_pin, uarttio_ports[i].rx_pin, + uarttio_ports[i].uart->current_baud_rate); + } + pr_info("Serial: Ubicom32 uarttio started on thread:%d irq:%d\n", uarttio_inst.regs->thread, uarttio_inst.irq); + + return ret; + +fail: + ubi32_uarttio_cleanup(); + return ret; +} +module_init(ubi32_uarttio_init); + +/* + * ubi32_uarttio_exit + */ +static void __exit ubi32_uarttio_exit(void) +{ + platform_driver_unregister(&ubi32_uarttio_platform_driver); +} +module_exit(ubi32_uarttio_exit); + +module_param_string(ports, utio_ports_param, sizeof(utio_ports_param), 0444); +MODULE_PARM_DESC(ports, "Sets the ports to allocate: ports=TIONAME,(baud,txpin,rxpin,handshake[,ctspin,rtspin],...)\n" + " TIONAME is the name of the devtree node which describes the UARTTIO\n" + " pin is the index of the pin, i.e. PA4 is 5 [(port * 32) + pin]\n" + " handshake = 1 to enable handshaking, provide ctspin, rtspin (UNSUPPORTED)\n" + " handshake = 0 to disable handshaking, do not provide ctspin, rtspin\n" + " Ex: ports=UARTTIO,57600,7,6,0,9600,8,9,0\n"); +MODULE_AUTHOR("Patrick Tjin "); +MODULE_DESCRIPTION("Ubicom serial virtual peripherial driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(UBI32_UARTTIO_MAJOR); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/target/linux/ubicom32/files/drivers/spi/spi_ubicom32_gpio.c b/target/linux/ubicom32/files/drivers/spi/spi_ubicom32_gpio.c new file mode 100644 index 000000000..c41018a26 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/spi/spi_ubicom32_gpio.c @@ -0,0 +1,267 @@ +/* + * drivers/spi_spi_ubicom32_gpio.c + * Ubicom32 GPIO based SPI driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#define DRIVER_NAME "ubicom32-spi-gpio" + +struct ubicom32_spi_gpio { + struct spi_bitbang bitbang; + + struct ubicom32_spi_gpio_platform_data *pdata; + + struct platform_device *dev; +}; + +/* + * The following 4 functions are used by EXPAND_BITBANG_TXRX to bitbang the data out. + */ +static inline void setsck(struct spi_device *dev, int on) +{ + struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master); + gpio_set_value(usg->pdata->pin_clk, on ? 1 : 0); +} + +static inline void setmosi(struct spi_device *dev, int on) +{ + struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master); + gpio_set_value(usg->pdata->pin_mosi, on ? 1 : 0); +} + +static inline u32 getmiso(struct spi_device *dev) +{ + struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master); + return gpio_get_value(usg->pdata->pin_miso) ? 1 : 0; +} + +#define spidelay(x) ndelay(x) + +#define EXPAND_BITBANG_TXRX +#include + +/* + * ubicom32_spi_gpio_txrx_mode0 + */ +static u32 ubicom32_spi_gpio_txrx_mode0(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); +} + +/* + * ubicom32_spi_gpio_txrx_mode1 + */ +static u32 ubicom32_spi_gpio_txrx_mode1(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits); +} + +/* + * ubicom32_spi_gpio_txrx_mode2 + */ +static u32 ubicom32_spi_gpio_txrx_mode2(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits); +} + +/* + * ubicom32_spi_gpio_txrx_mode3 + */ +static u32 ubicom32_spi_gpio_txrx_mode3(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits); +} + +/* + * ubicom32_spi_gpio_chipselect + */ +static void ubicom32_spi_gpio_chipselect(struct spi_device *dev, int value) +{ + struct ubicom32_spi_gpio_controller_data *cd = (struct ubicom32_spi_gpio_controller_data *)dev->controller_data; + unsigned int cs_polarity = dev->mode & SPI_CS_HIGH ? 1 : 0; + + if (value == BITBANG_CS_ACTIVE) { + gpio_set_value(cd->pin_cs, cs_polarity); + return; + } + gpio_set_value(cd->pin_cs, !cs_polarity); +} + +/* + * ubicom32_spi_gpio_probe + */ +static int ubicom32_spi_gpio_probe(struct platform_device *dev) +{ + struct ubicom32_spi_gpio_platform_data *pdata; + struct spi_master *master; + struct ubicom32_spi_gpio *usg; + int ret; + + master = spi_alloc_master(&dev->dev, sizeof(struct ubicom32_spi_gpio)); + if (master == NULL) { + dev_err(&dev->dev, "failed to allocate spi master\n"); + ret = -ENOMEM; + goto err; + } + + usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(master); + + platform_set_drvdata(dev, usg); + + /* + * Copy in the platform data + */ + pdata = dev->dev.platform_data; + usg->pdata = dev->dev.platform_data; + + /* + * Request the GPIO lines + */ + ret = gpio_request(pdata->pin_mosi, "spi-mosi"); + if (ret) { + dev_err(&dev->dev, "Failed to allocate spi-mosi GPIO\n"); + goto err; + } + + ret = gpio_request(pdata->pin_miso, "spi-miso"); + if (ret) { + dev_err(&dev->dev, "Failed to allocate spi-miso GPIO\n"); + goto err_nomiso; + } + + ret = gpio_request(pdata->pin_clk, "spi-clk"); + if (ret) { + dev_err(&dev->dev, "Failed to allocate spi-clk GPIO\n"); + goto err_noclk; + } + + /* + * Setup spi-bitbang adaptor + */ + usg->bitbang.flags |= SPI_CS_HIGH; + usg->bitbang.master = spi_master_get(master); + usg->bitbang.master->bus_num = pdata->bus_num; + usg->bitbang.master->num_chipselect = pdata->num_chipselect; + usg->bitbang.chipselect = ubicom32_spi_gpio_chipselect; + + usg->bitbang.txrx_word[SPI_MODE_0] = ubicom32_spi_gpio_txrx_mode0; + usg->bitbang.txrx_word[SPI_MODE_1] = ubicom32_spi_gpio_txrx_mode1; + usg->bitbang.txrx_word[SPI_MODE_2] = ubicom32_spi_gpio_txrx_mode2; + usg->bitbang.txrx_word[SPI_MODE_3] = ubicom32_spi_gpio_txrx_mode3; + + /* + * Setup the GPIO pins + */ + gpio_direction_output(pdata->pin_clk, pdata->clk_default); + gpio_direction_output(pdata->pin_mosi, 0); + gpio_direction_input(pdata->pin_miso); + + /* + * Ready to go + */ + ret = spi_bitbang_start(&usg->bitbang); + if (ret) { + goto err_no_bitbang; + } + + return 0; + +err_no_bitbang: + spi_master_put(usg->bitbang.master); + + gpio_free(pdata->pin_clk); + +err_noclk: + gpio_free(pdata->pin_miso); + +err_nomiso: + gpio_free(pdata->pin_mosi); + +err: + return ret; +} + +/* + * ubicom32_spi_gpio_remove + */ +static int ubicom32_spi_gpio_remove(struct platform_device *dev) +{ + struct ubicom32_spi_gpio *sp = platform_get_drvdata(dev); + + spi_bitbang_stop(&sp->bitbang); + spi_master_put(sp->bitbang.master); + + return 0; +} + +/* + * Work with hotplug and coldplug + */ +MODULE_ALIAS("platform:ubicom32_spi_gpio"); + +static struct platform_driver ubicom32_spi_gpio_drv = { + .probe = ubicom32_spi_gpio_probe, + .remove = ubicom32_spi_gpio_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +/* + * ubicom32_spi_gpio_init + */ +static int __init ubicom32_spi_gpio_init(void) +{ + return platform_driver_register(&ubicom32_spi_gpio_drv); +} + +/* + * ubicom32_spi_gpio_exit + */ +static void __exit ubicom32_spi_gpio_exit(void) +{ + platform_driver_unregister(&ubicom32_spi_gpio_drv); +} + +module_init(ubicom32_spi_gpio_init); +module_exit(ubicom32_spi_gpio_exit); + +MODULE_DESCRIPTION("Ubicom32 SPI-GPIO Driver"); +MODULE_AUTHOR("Pat Tjin, <@ubicom.com>"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/drivers/uio/uio_ubicom32ring.c b/target/linux/ubicom32/files/drivers/uio/uio_ubicom32ring.c new file mode 100644 index 000000000..654ac4ced --- /dev/null +++ b/target/linux/ubicom32/files/drivers/uio/uio_ubicom32ring.c @@ -0,0 +1,288 @@ +/* + * drivers/uio/uio_ubicom32ring.c + * + * Userspace I/O platform driver for Ubicom32 ring buffers + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * Based on uio_ubicom32ring.c by Magnus Damm + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "uio_ubicom32ring" + +struct uio_ubicom32ring_data { + struct uio_info *uioinfo; + + struct uio_ubicom32ring_regs *regs; + + /* + * IRQ used to kick the ring buffer + */ + int irq_tx; + int irq_rx; + + spinlock_t lock; + + unsigned long flags; + + char name[0]; +}; + +static irqreturn_t uio_ubicom32ring_handler(int irq, struct uio_info *dev_info) +{ + struct uio_ubicom32ring_data *priv = dev_info->priv; + + /* Just disable the interrupt in the interrupt controller, and + * remember the state so we can allow user space to enable it later. + */ + + if (!test_and_set_bit(0, &priv->flags)) + disable_irq_nosync(irq); + + return IRQ_HANDLED; +} + +static int uio_ubicom32ring_irqcontrol(struct uio_info *dev_info, s32 irq_on) +{ + struct uio_ubicom32ring_data *priv = dev_info->priv; + unsigned long flags; + + /* Allow user space to enable and disable the interrupt + * in the interrupt controller, but keep track of the + * state to prevent per-irq depth damage. + * + * Serialize this operation to support multiple tasks. + */ + + spin_lock_irqsave(&priv->lock, flags); + + if (irq_on & 2) { + /* + * Kick the ring buffer (if we can) + */ + if (priv->irq_tx != 0xFF) { + ubicom32_set_interrupt(priv->irq_tx); + } + } + + if (priv->irq_rx != 0xFF) { + if (irq_on & 1) { + if (test_and_clear_bit(0, &priv->flags)) + enable_irq(dev_info->irq); + } else { + if (!test_and_set_bit(0, &priv->flags)) + disable_irq(dev_info->irq); + } + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int uio_ubicom32ring_probe(struct platform_device *pdev) +{ + struct uio_info *uioinfo; + struct uio_mem *uiomem; + struct uio_ubicom32ring_data *priv; + struct uio_ubicom32ring_regs *regs; + struct resource *mem_resource; + struct resource *irqtx_resource; + struct resource *irqrx_resource; + int ret = -EINVAL; + int i; + + uioinfo = kzalloc(sizeof(struct uio_info), GFP_KERNEL); + if (!uioinfo) { + dev_err(&pdev->dev, "unable to kmalloc\n"); + return -ENOMEM; + } + + /* + * Allocate private data with some string space after + */ + i = sizeof(DRIVER_NAME) + 1; + i += pdev->dev.platform_data ? strlen(pdev->dev.platform_data) : 0; + priv = kzalloc(sizeof(struct uio_ubicom32ring_data) + i, GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "unable to kmalloc\n"); + kfree(uioinfo); + return -ENOMEM; + } + + strcpy(priv->name, DRIVER_NAME ":"); + if (pdev->dev.platform_data) { + strcat(priv->name, pdev->dev.platform_data); + } + uioinfo->priv = priv; + uioinfo->name = priv->name; + uioinfo->version = "0.1"; + + priv->uioinfo = uioinfo; + spin_lock_init(&priv->lock); + priv->flags = 0; /* interrupt is enabled to begin with */ + + /* + * Get our resources, the IRQ_TX and IRQ_RX are optional. + */ + priv->irq_tx = 0xFF; + irqtx_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (irqtx_resource) { + priv->irq_tx = irqtx_resource->start; + } + + uioinfo->irq = -1; + priv->irq_rx = 0xFF; + irqrx_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (irqrx_resource) { + priv->irq_rx = irqrx_resource->start; + uioinfo->irq = priv->irq_rx; + uioinfo->handler = uio_ubicom32ring_handler; + } + + mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_resource || !mem_resource->start) { + dev_err(&pdev->dev, "No valid memory resource found\n"); + ret = -ENODEV; + goto fail; + } + regs = (struct uio_ubicom32ring_regs *)mem_resource->start; + priv->regs = regs; + + if (regs->version != UIO_UBICOM32RING_REG_VERSION) { + dev_err(&pdev->dev, "version %d not supported\n", regs->version); + ret = -ENODEV; + goto fail; + } + + /* + * First range is the shared register space, if we have any + */ + uiomem = &uioinfo->mem[0]; + if (regs->regs_size) { + uiomem->memtype = UIO_MEM_PHYS; + uiomem->addr = (u32_t)regs->regs; + uiomem->size = regs->regs_size; + ++uiomem; + dev_info(&pdev->dev, "regs:%p (%u) / rings: %d found\n", regs->regs, regs->regs_size, regs->num_rings); + } else { + dev_info(&pdev->dev, "rings: %d found\n", regs->num_rings); + } + + /* + * The rest of the range correspond to the rings + */ + for (i = 0; i < regs->num_rings; i++) { + dev_info(&pdev->dev, "\t%d: entries:%d ring:%p\n", + i, regs->rings[i]->entries, &(regs->rings[i]->ring)); + if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { + dev_warn(&pdev->dev, "device has more than " + __stringify(MAX_UIO_MAPS) + " I/O memory resources.\n"); + break; + } + + uiomem->memtype = UIO_MEM_PHYS; + uiomem->addr = (u32_t)&(regs->rings[i]->head); + uiomem->size = (regs->rings[i]->entries * sizeof(u32_t)) + + sizeof(struct uio_ubicom32ring_desc); + ++uiomem; + } + + while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) { + uiomem->size = 0; + ++uiomem; + } + + /* This driver requires no hardware specific kernel code to handle + * interrupts. Instead, the interrupt handler simply disables the + * interrupt in the interrupt controller. User space is responsible + * for performing hardware specific acknowledge and re-enabling of + * the interrupt in the interrupt controller. + * + * Interrupt sharing is not supported. + */ + uioinfo->irq_flags = IRQF_DISABLED; + uioinfo->irqcontrol = uio_ubicom32ring_irqcontrol; + + ret = uio_register_device(&pdev->dev, priv->uioinfo); + if (ret) { + dev_err(&pdev->dev, "unable to register uio device\n"); + goto fail; + } + + platform_set_drvdata(pdev, priv); + + dev_info(&pdev->dev, "'%s' using irq: rx %d tx %d, regs %p\n", + priv->name, priv->irq_rx, priv->irq_tx, priv->regs); + + return 0; + +fail: + kfree(uioinfo); + kfree(priv); + return ret; +} + +static int uio_ubicom32ring_remove(struct platform_device *pdev) +{ + struct uio_ubicom32ring_data *priv = platform_get_drvdata(pdev); + + uio_unregister_device(priv->uioinfo); + kfree(priv->uioinfo); + kfree(priv); + return 0; +} + +static struct platform_driver uio_ubicom32ring = { + .probe = uio_ubicom32ring_probe, + .remove = uio_ubicom32ring_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init uio_ubicom32ring_init(void) +{ + return platform_driver_register(&uio_ubicom32ring); +} + +static void __exit uio_ubicom32ring_exit(void) +{ + platform_driver_unregister(&uio_ubicom32ring); +} + +module_init(uio_ubicom32ring_init); +module_exit(uio_ubicom32ring_exit); + +MODULE_AUTHOR("Patrick Tjin"); +MODULE_DESCRIPTION("Userspace I/O driver for Ubicom32 ring buffers"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/target/linux/ubicom32/files/drivers/usb/musb/ubi32_usb.c b/target/linux/ubicom32/files/drivers/usb/musb/ubi32_usb.c new file mode 100644 index 000000000..d89e00416 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/usb/musb/ubi32_usb.c @@ -0,0 +1,156 @@ +/* + * drivers/usb/musb/ubi32_usb.c + * Ubicom32 usb controller driver. + * + * (C) Copyright 2009, Ubicom, Inc. + * Copyright (C) 2005-2006 by Texas Instruments + * + * Derived from the Texas Instruments Inventra Controller Driver for Linux. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "musb_core.h" + +void musb_platform_enable(struct musb *musb) +{ +} +void musb_platform_disable(struct musb *musb) +{ +} + +int musb_platform_set_mode(struct musb *musb, u8 musb_mode) { + return 0; +} + +static void ip5k_usb_hcd_vbus_power(struct musb *musb, int is_on, int sleeping) +{ +} + +static void ip5k_usb_hcd_set_vbus(struct musb *musb, int is_on) +{ + u8 devctl; + /* HDRC controls CPEN, but beware current surges during device + * connect. They can trigger transient overcurrent conditions + * that must be ignored. + */ + + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + + if (is_on) { + musb->is_active = 1; + musb->xceiv.default_a = 1; + musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; + devctl |= MUSB_DEVCTL_SESSION; + + MUSB_HST_MODE(musb); + } else { + musb->is_active = 0; + + /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and + * jumping right to B_IDLE... + */ + + musb->xceiv.default_a = 0; + musb->xceiv.state = OTG_STATE_B_IDLE; + devctl &= ~MUSB_DEVCTL_SESSION; + + MUSB_DEV_MODE(musb); + } + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + + DBG(1, "VBUS %s, devctl %02x " + /* otg %3x conf %08x prcm %08x */ "\n", + otg_state_string(musb), + musb_readb(musb->mregs, MUSB_DEVCTL)); +} +static int ip5k_usb_hcd_set_power(struct otg_transceiver *x, unsigned mA) +{ + return 0; +} + +static int musb_platform_resume(struct musb *musb); + +int __init musb_platform_init(struct musb *musb) +{ + +#ifdef CONFIG_UBICOM32_V4 + u32_t chip_id; + asm volatile ( + "move.4 %0, CHIP_ID \n\t" + : "=r" (chip_id) + ); + if (chip_id == 0x30001) { + *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 30); + udelay(1); + *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 31); + } else { + *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 17); + udelay(1); + *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 14); + } +#endif + + *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_CFG)) |= ((1 << 14) | (1 <<15)); + + /* The i-clk is AUTO gated. Hence there is no need + * to disable it until the driver is shutdown */ + + clk_enable(musb->clock); + musb_platform_resume(musb); + + ip5k_usb_hcd_vbus_power(musb, musb->board_mode == MUSB_HOST, 1); + + if (is_host_enabled(musb)) + musb->board_set_vbus = ip5k_usb_hcd_set_vbus; + if (is_peripheral_enabled(musb)) + musb->xceiv.set_power = ip5k_usb_hcd_set_power; + + return 0; +} + + +int musb_platform_suspend(struct musb *musb) +{ + return 0; +} +int musb_platform_resume(struct musb *musb) +{ + return 0; +} + +int musb_platform_exit(struct musb *musb) +{ + ip5k_usb_hcd_vbus_power(musb, 0 /*off*/, 1); + musb_platform_suspend(musb); + return 0; +} diff --git a/target/linux/ubicom32/files/drivers/video/backlight/ubicom32bl.c b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32bl.c new file mode 100644 index 000000000..99538c341 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32bl.c @@ -0,0 +1,399 @@ +/* + * drivers/video/backlight/ubicom32bl.c + * Backlight driver for the Ubicom32 platform + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "ubicom32bl" +#define UBICOM32BL_MAX_BRIGHTNESS 255 + +struct ubicom32bl_data { + /* + * Pointer to the platform data structure. Keep this around since we need values + * from it to set the backlight intensity. + */ + const struct ubicom32bl_platform_data *pdata; + + /* + * Backlight device, we have to save this for use when we remove ourselves. + */ + struct backlight_device *bldev; + + /* + * Current intensity, used for get_intensity. + */ + int cur_intensity; + + /* + * Init function for PWM + */ + int (*init_fn)(struct ubicom32bl_data *); + + /* + * Set intensity function depending on the backlight type + */ + int (*set_intensity_fn)(struct ubicom32bl_data *, int); +}; + +/* + * ubicom32bl_set_intensity_gpio + */ +static int ubicom32bl_set_intensity_gpio(struct ubicom32bl_data *ud, int intensity) +{ + ud->cur_intensity = intensity ? 255 : 0; + + if (intensity) { + // set gpio + return 0; + } + + // clear gpio + return 0; +} + +/* + * ubicom32bl_set_intensity_hw + */ +static int ubicom32bl_set_intensity_hw(struct ubicom32bl_data *ud, int intensity) +{ + u16_t period = ud->pdata->pwm_period; + u16_t duty; + + /* + * Calculate the new duty cycle + */ + duty = (period * intensity) / (UBICOM32BL_MAX_BRIGHTNESS + 1); + + /* + * Set the new duty cycle + */ + switch (ud->pdata->pwm_channel) { + case 0: + /* + * Channel 0 is in the lower half of PORT C ctl0 and ctl1 + */ + UBICOM32_IO_PORT(RC)->ctl1 = (ud->pdata->pwm_period << 16) | duty; + break; + + case 1: + /* + * Channel 1 is in the upper half of PORT C ctl0 and ctl2 + */ + UBICOM32_IO_PORT(RC)->ctl2 = (ud->pdata->pwm_period << 16) | duty; + break; + + case 2: + /* + * Channel 2 is in PORT H ctl0 and ctl1 + */ + UBICOM32_IO_PORT(RH)->ctl1 = (ud->pdata->pwm_period << 16) | duty; + break; + } + + ud->cur_intensity = intensity; + + return 0; +} + +/* + * ubicom32bl_set_intensity + */ +static int ubicom32bl_set_intensity(struct backlight_device *bd) +{ + struct ubicom32bl_data *ud = (struct ubicom32bl_data *)bl_get_data(bd); + int intensity = bd->props.brightness; + + /* + * If we're blanked the the intensity doesn't matter. + */ + if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) { + intensity = 0; + } + + /* + * Check for inverted backlight. + */ + if (ud->pdata->invert) { + intensity = UBICOM32BL_MAX_BRIGHTNESS - intensity; + } + + if (ud->set_intensity_fn) { + return ud->set_intensity_fn(ud, intensity); + } + + return -ENXIO; +} + +/* + * ubicom32bl_get_intensity + * Return the current intensity of the backlight. + */ +static int ubicom32bl_get_intensity(struct backlight_device *bd) +{ + struct ubicom32bl_data *ud = (struct ubicom32bl_data *)bl_get_data(bd); + + return ud->cur_intensity; +} + +/* + * ubicom32bl_init_hw_pwm + * Set the appropriate PWM registers + */ +static int ubicom32bl_init_hw_pwm(struct ubicom32bl_data *ud) +{ + /* + * bit 13: enable + */ + u16_t pwm_cfg = (1 << 13) | (ud->pdata->pwm_prescale << 8) ; + + switch (ud->pdata->pwm_channel) { + case 0: + /* + * Channel 0 is in the lower half of PORT C ctl0 and ctl1 (PA5) + */ + UBICOM32_IO_PORT(RC)->ctl0 &= ~0xFFFF; + UBICOM32_IO_PORT(RC)->ctl0 |= pwm_cfg; + UBICOM32_IO_PORT(RC)->ctl1 = ud->pdata->pwm_period << 16; + + /* + * If the port function is not set, set it to GPIO/PWM + */ + if (!UBICOM32_IO_PORT(RA)->function) { + UBICOM32_IO_PORT(RA)->function = 3; + } + break; + + case 1: + /* + * Channel 1 is in the upper half of PORT C ctl0 and ctl2 (PE4) + */ + UBICOM32_IO_PORT(RC)->ctl0 &= ~0xFFFF0000; + UBICOM32_IO_PORT(RC)->ctl0 |= (pwm_cfg << 16); + UBICOM32_IO_PORT(RC)->ctl2 = ud->pdata->pwm_period << 16; + + /* + * If the port function is not set, set it to GPIO/ExtIOInt + */ + if (!UBICOM32_IO_PORT(RE)->function) { + UBICOM32_IO_PORT(RE)->function = 3; + } + break; + + case 2: + /* + * Channel 2 is in PORT H ctl0 and ctl1 (PD0) + */ + UBICOM32_IO_PORT(RH)->ctl0 &= ~0xFFFF0000; + UBICOM32_IO_PORT(RH)->ctl0 = pwm_cfg; + UBICOM32_IO_PORT(RH)->ctl1 = ud->pdata->pwm_period << 16; + + /* + * If the port function is not set, set it to GPIO + */ + if (!UBICOM32_IO_PORT(RD)->function) { + UBICOM32_IO_PORT(RD)->function = 3; + } + break; + } + + return 0; +} + +/* + * ubicom32bl_init_gpio + * Allocate the appropriate GPIO + */ +static int ubicom32bl_init_gpio(struct ubicom32bl_data *ud) +{ + return 0; +} + +static struct backlight_ops ubicom32bl_ops = { + .get_brightness = ubicom32bl_get_intensity, + .update_status = ubicom32bl_set_intensity, +}; + +/* + * ubicom32bl_probe + */ +static int ubicom32bl_probe(struct platform_device *pdev) +{ + const struct ubicom32bl_platform_data *pdata = pdev->dev.platform_data; + struct ubicom32bl_data *ud; + struct backlight_device *bldev; + int retval; + + /* + * Check to see if we have any platform data, if we don't then the backlight is not + * configured on this device. + */ + if (!pdata) { + return -ENODEV; + } + + /* + * Allocate our private data + */ + ud = kzalloc(sizeof(struct ubicom32bl_data), GFP_KERNEL); + if (!ud) { + return -ENOMEM; + } + + ud->pdata = pdata; + + /* + * Check to see that the platform data is valid for this driver + */ + switch (pdata->type) { + case UBICOM32BL_TYPE_PWM: + { + /* + * Make sure we have a PWM peripheral + */ + u32_t chipid; + asm volatile ( + "move.4 %0, CHIP_ID \n\t" + : "=r" (chipid) + ); + if (chipid != 0x00030001) { + retval = -ENODEV; + goto fail; + } + + if (pdata->pwm_channel > 3) { + retval = -ENODEV; + goto fail; + } + if (pdata->pwm_prescale > 16) { + retval = -EINVAL; + goto fail; + } + + ud->init_fn = ubicom32bl_init_hw_pwm; + ud->set_intensity_fn = ubicom32bl_set_intensity_hw; + break; + } + + case UBICOM32BL_TYPE_PWM_HRT: + // For now, PWM HRT devices are treated as binary lights. + + case UBICOM32BL_TYPE_BINARY: + ud->init_fn = ubicom32bl_init_gpio; + ud->set_intensity_fn = ubicom32bl_set_intensity_gpio; + break; + } + + /* + * Register our backlight device + */ + bldev = backlight_device_register(DRIVER_NAME, &pdev->dev, ud, &ubicom32bl_ops); + if (IS_ERR(bldev)) { + retval = PTR_ERR(bldev); + goto fail; + } + + ud->bldev = bldev; + ud->cur_intensity = pdata->default_intensity; + platform_set_drvdata(pdev, ud); + + /* + * Start up the backlight at the prescribed default intensity + */ + bldev->props.power = FB_BLANK_UNBLANK; + bldev->props.max_brightness = UBICOM32BL_MAX_BRIGHTNESS; + bldev->props.brightness = pdata->default_intensity; + + if (ud->init_fn) { + if (ud->init_fn(ud) != 0) { + retval = -ENODEV; + backlight_device_unregister(ud->bldev); + goto fail; + } + } + ubicom32bl_set_intensity(bldev); + + printk(KERN_INFO DRIVER_NAME ": Backlight driver started\n"); + + return 0; + +fail: + platform_set_drvdata(pdev, NULL); + kfree(ud); + return retval; +} + +/* + * ubicom32bl_remove + */ +static int __exit ubicom32bl_remove(struct platform_device *pdev) +{ + struct ubicom32bl_data *ud = platform_get_drvdata(pdev); + + backlight_device_unregister(ud->bldev); + platform_set_drvdata(pdev, NULL); + kfree(ud); + + return 0; +} + +static struct platform_driver ubicom32bl_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + + .remove = __exit_p(ubicom32bl_remove), +}; + +/* + * ubicom32bl_init + */ +static int __init ubicom32bl_init(void) +{ + return platform_driver_probe(&ubicom32bl_driver, ubicom32bl_probe); +} +module_init(ubicom32bl_init); + +/* + * ubicom32bl_exit + */ +static void __exit ubicom32bl_exit(void) +{ + platform_driver_unregister(&ubicom32bl_driver); +} +module_exit(ubicom32bl_exit); + +MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); +MODULE_DESCRIPTION("Ubicom32 backlight driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.c b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.c new file mode 100644 index 000000000..e4f8c713e --- /dev/null +++ b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.c @@ -0,0 +1,372 @@ +/* + * drivers/video/ubicom32lcd.c + * LCD initilization code + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ubicom32lcd.h" + +#define DRIVER_NAME "ubicom32lcd" + +struct ubicom32lcd_data { + const struct ubicom32lcd_panel *panel; + + int pin_cs; + int pin_rd; + int pin_rs; + int pin_wr; + int pin_reset; + struct ubicom32_io_port *port_data; + int data_shift; +}; + +/* + * ubicom32lcd_write + * Performs a write cycle on the bus (assumes CS asserted, RD & WR set) + */ +static void ubicom32lcd_write(struct ubicom32lcd_data *ud, int command, u16 data) +{ + if (command) { + UBICOM32_GPIO_SET_PIN_LOW(ud->pin_rs); + } else { + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs); + } + + asm volatile ( + "or.4 4(%[port]), 4(%[port]), %[mask] \n\t" + "not.4 %[mask], %[mask] \n\t" + "and.4 8(%[port]), 8(%[port]), %[mask] \n\t" + "or.4 8(%[port]), 8(%[port]), %[cmd] \n\t" + : + : [port] "a" (ud->port_data), + [mask] "d" (0xFFFF << ud->data_shift), + [cmd] "d" (data << ud->data_shift) + : "cc" + ); + + UBICOM32_GPIO_SET_PIN_LOW(ud->pin_wr); + + //ndelay(50); + udelay(1); + + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr); + + udelay(1); + //ndelay(50); +} + +/* + * ubicom32lcd_read_data + * Performs a read cycle on the bus (assumes CS asserted, RD & WR set) + */ +static u16 ubicom32lcd_read_data(struct ubicom32lcd_data *ud) +{ + u32_t data; + + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs); + + asm volatile ( + "and.4 4(%[port]), 4(%[port]), %[mask]\n\t" + : + : [port] "a" (ud->port_data), + [mask] "d" (~(0xFFFF << ud->data_shift)) + : "cc" + ); + + UBICOM32_GPIO_SET_PIN_LOW(ud->pin_rd); + + ndelay(300); + + asm volatile ( + "lsr.4 %[data], 12(%[port]), %[shamt] \n\t" + "and.4 %[data], %[data], %[mask] \n\t" + : [data] "=d" (data) + : [port] "a" (ud->port_data), + [mask] "d" (0xFFFF), + [shamt] "d" (ud->data_shift) + : "cc" + ); + + ndelay(200); + + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd); + + ndelay(500); + + return data; +} + +/* + * ubicom32lcd_execute + * Executes a script for performing operations on the LCD (assumes CS set) + */ +static void ubicom32lcd_execute(struct ubicom32lcd_data *ud, const struct ubicom32lcd_step *script) +{ + while (1) { + switch (script->op) { + case LCD_STEP_CMD: + ubicom32lcd_write(ud, 1, script->cmd); + break; + + case LCD_STEP_DATA: + ubicom32lcd_write(ud, 0, script->data); + break; + + case LCD_STEP_CMD_DATA: + ubicom32lcd_write(ud, 1, script->cmd); + ubicom32lcd_write(ud, 0, script->data); + break; + + case LCD_STEP_SLEEP: + udelay(script->data); + break; + + case LCD_STEP_DONE: + return; + } + script++; + } +} + +/* + * ubicom32lcd_goto + * Places the gram pointer at a specific X, Y address + */ +static void ubicom32lcd_goto(struct ubicom32lcd_data *ud, int x, int y) +{ + ubicom32lcd_write(ud, 1, ud->panel->horz_reg); + ubicom32lcd_write(ud, 0, x); + ubicom32lcd_write(ud, 1, ud->panel->vert_reg); + ubicom32lcd_write(ud, 0, y); + ubicom32lcd_write(ud, 1, ud->panel->gram_reg); +} + +/* + * ubicom32lcd_panel_init + * Initializes the lcd panel. + */ +static int ubicom32lcd_panel_init(struct ubicom32lcd_data *ud) +{ + u16 id; + + UBICOM32_GPIO_SET_PIN_LOW(ud->pin_reset); + UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_reset); + UBICOM32_GPIO_ENABLE(ud->pin_reset); + + asm volatile ( + "or.4 0x50(%[port]), 0x50(%[port]), %[mask] \n\t" + "not.4 %[mask], %[mask] \n\t" + "and.4 0x04(%[port]), 0x04(%[port]), %[mask] \n\t" + : + : [port] "a" (ud->port_data), + [mask] "d" (0xFFFF << ud->data_shift) + : "cc" + ); + + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs); + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd); + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr); + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs); + + UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_rs); + UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_rd); + UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_wr); + UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_cs); + + UBICOM32_GPIO_ENABLE(ud->pin_rs); + UBICOM32_GPIO_ENABLE(ud->pin_rd); + UBICOM32_GPIO_ENABLE(ud->pin_wr); + UBICOM32_GPIO_ENABLE(ud->pin_cs); + + udelay(20); + + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_reset); + + udelay(20); + + UBICOM32_GPIO_SET_PIN_LOW(ud->pin_cs); + + id = ubicom32lcd_read_data(ud); + + /* + * We will try to figure out what kind of panel we have if we were not told. + */ + if (!ud->panel) { + const struct ubicom32lcd_panel **p = ubicom32lcd_panels; + while (*p) { + if ((*p)->id && ((*p)->id == id)) { + break; + } + p++; + } + if (!*p) { + printk(KERN_WARNING DRIVER_NAME ":Could not find compatible panel, id=%x\n", id); + return -ENODEV; + } + ud->panel = *p; + } + + /* + * Make sure panel ID matches if we were supplied a panel type + */ + if (ud->panel->id && (ud->panel->id != id)) { + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs); + + return -ENODEV; + } + + ubicom32lcd_execute(ud, ud->panel->init_seq); + + ubicom32lcd_goto(ud, 0, 0); + + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs); + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd); + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr); + UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs); + + printk(KERN_INFO DRIVER_NAME ": Initialized panel %s\n", ud->panel->desc); + + return 0; +} + +/* + * ubicom32lcd_probe + */ +static int ubicom32lcd_probe(struct platform_device *pdev) +{ + const struct ubicom32lcd_platform_data *pdata = pdev->dev.platform_data; + struct ubicom32lcd_data *ud; + int retval; + + /* + * Allocate our private data + */ + ud = kzalloc(sizeof(struct ubicom32lcd_data), GFP_KERNEL); + if (!ud) { + return -ENOMEM; + } + + if (pdata) { + ud->pin_cs = pdata->pin_cs; + ud->pin_rd = pdata->pin_rd; + ud->pin_wr = pdata->pin_wr; + ud->pin_rs = pdata->pin_rs; + ud->pin_reset = pdata->pin_reset; + ud->port_data = pdata->port_data; + ud->data_shift = pdata->data_shift; + } else { + /* + * Defaults + */ + ud->pin_cs = GPIO_RD_4; + ud->pin_rd = GPIO_RD_5; + ud->pin_rs = GPIO_RD_3; + ud->pin_wr = GPIO_RD_2; + ud->pin_reset = GPIO_RD_7; + ud->port_data = (struct ubicom32_io_port *)RI; + ud->data_shift = 0; + } + + /* + * Initialize the display + */ + retval = ubicom32lcd_panel_init(ud); + if (retval) { + kfree(ud); + return retval; + } + + printk(KERN_INFO DRIVER_NAME ": LCD initialized\n"); + + return 0; +} + +/* + * ubicom32lcd_remove + */ +static int __exit ubicom32lcd_remove(struct platform_device *pdev) +{ + struct ubicom32lcd_data *ud = platform_get_drvdata(pdev); + + kfree(ud); + + return 0; +} + +static struct platform_driver ubicom32lcd_driver = { + .probe = ubicom32lcd_probe, + .remove = ubicom32lcd_remove, + + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + + .remove = __exit_p(ubicom32lcd_remove), +}; + +static struct platform_device *ubicom32lcd_device; + +/* + * ubicom32lcd_init + */ +static int __init ubicom32lcd_init(void) +{ + int res; + + res = platform_driver_register(&ubicom32lcd_driver); + if (res == 0) { + ubicom32lcd_device = platform_device_alloc(DRIVER_NAME, 0); + if (ubicom32lcd_device) { + res = platform_device_add(ubicom32lcd_device); + } else { + res = -ENOMEM; + } + if (res) { + platform_device_put(ubicom32lcd_device); + platform_driver_unregister(&ubicom32lcd_driver); + } + } + return res; +} +module_init(ubicom32lcd_init); + +/* + * ubicom32lcd_exit + */ +static void __exit ubicom32lcd_exit(void) +{ + platform_device_unregister(ubicom32lcd_device); + platform_driver_unregister(&ubicom32lcd_driver); +} +module_exit(ubicom32lcd_exit); + +MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); +MODULE_DESCRIPTION("Ubicom32 LCD driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.h b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.h new file mode 100644 index 000000000..07650ba9e --- /dev/null +++ b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.h @@ -0,0 +1,546 @@ +/* + * ubicom32lcd.h + * Ubicom32 lcd panel drivers + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * This Ubicom32 library is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This Ubicom32 library is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#ifndef _UBICOM32LCD_H_ +#define _UBICOM32LCD_H_ + +enum ubicom32lcd_op { + /* + * Sleep for (data) ms + */ + LCD_STEP_SLEEP, + + /* + * Execute write of command + */ + LCD_STEP_CMD, + + /* + * Execute write of data + */ + LCD_STEP_DATA, + + /* + * Execute write of command/data + */ + LCD_STEP_CMD_DATA, + + /* + * Script done + */ + LCD_STEP_DONE, +}; + +struct ubicom32lcd_step { + enum ubicom32lcd_op op; + u16 cmd; + u16 data; +}; + +struct ubicom32lcd_panel { + const struct ubicom32lcd_step *init_seq; + const char *desc; + + u32 xres; + u32 yres; + u32 stride; + u32 flags; + + u16 id; + u16 horz_reg; + u16 vert_reg; + u16 gram_reg; +}; + +#ifdef CONFIG_LCD_UBICOM32_CFAF240320KTTS +static const struct ubicom32lcd_step cfaf240320ktts_init_0[] = { + {LCD_STEP_CMD_DATA, 0x0001, 0x0000,}, // Driver Output Control Register (R01h) Page 14, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0002, 0x0700,}, // LCD Driving Waveform Control (R02h) Page 15, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0003, 0x50A0,}, // Entry Mode (R03h) 0 degrees + {LCD_STEP_CMD_DATA, 0x0004, 0x0000,}, // Scaling Control register (R04h) Page 16, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0008, 0x0207,}, // Display Control 2 (R08h) Page 17, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0009, 0x0000,}, // Display Control 3 (R09h) Page 18, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x000A, 0x0000,}, // Frame Cycle Control (R0Ah) Page 19, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x000C, 0x0000,}, // External Display Interface Control 1 (R0Ch) Page 20, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x000D, 0x0000,}, // Frame Maker Position (R0Dh) Page 21, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x000F, 0x0000,}, // External Display Interface Control 2 (R0Fh) Page 21, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0010, 0x0000,}, // Power Control 1 (R10h) Page 22, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h) Page 23, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0012, 0x0000,}, // Power Control 3 (R12h) Page 24, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0013, 0x0000,}, // Power Control 4 (R13h) Page 25, SPFD5408B Datasheet + {LCD_STEP_SLEEP, 0, 200}, + {LCD_STEP_CMD_DATA, 0x0007, 0x0101,}, // Display Control (R07h) Page 16, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0010, 0x12B0,}, // Power Control 1 (R10h) Page 22, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h) Page 23, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0012, 0x01BB,}, // Power Control 3 (R12h) Page 24, SPFD5408B Datasheet + {LCD_STEP_SLEEP, 0, 50}, + {LCD_STEP_CMD_DATA, 0x0013, 0x1300,}, // Power Control 4 (R13h) Page 25, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0029, 0x0010,}, // NVM read data 2 (R29h) Page 30, SPFD5408B Datasheet + {LCD_STEP_SLEEP, 0, 50}, + {LCD_STEP_CMD_DATA, 0x0030, 0x000A,}, // Gamma Control 1 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0031, 0x1326,}, // Gamma Control 2 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0032, 0x0A29,}, // Gamma Control 3 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0033, 0x290A,}, // Gamma Control 4 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0034, 0x2613,}, // Gamma Control 5 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0035, 0x0A0A,}, // Gamma Control 6 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0036, 0x1E03,}, // Gamma Control 7 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0037, 0x031E,}, // Gamma Control 8 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0038, 0x0706,}, // Gamma Control 9 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0039, 0x0303,}, // Gamma Control 10 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003A, 0x0E04,}, // Gamma Control 11 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003B, 0x0E01,}, // Gamma Control 12 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003C, 0x010E,}, // Gamma Control 13 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003D, 0x040E,}, // Gamma Control 14 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003E, 0x0303,}, // Gamma Control 15 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003F, 0x0607,}, // Gamma Control 16 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0050, 0x0000,}, // Window Horizontal RAM Address Start (R50h) Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0051, 0x00EF,}, // Window Horizontal RAM Address End (R51h) Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0052, 0x0000,}, // Window Vertical RAM Address Start (R52h) Page 33, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0053, 0x013F,}, // Window Vertical RAM Address End (R53h) Page 33, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0060, 0x2700,}, // Driver Output Control (R60h) Page 33, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0061, 0x0001,}, // Driver Output Control (R61h) Page 35, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x006A, 0x0000,}, // Vertical Scroll Control (R6Ah) Page 35, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0080, 0x0000,}, // Display Position - Partial Display 1 (R80h) Page 35, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0081, 0x0000,}, // RAM Address Start - Partial Display 1 (R81h) Page 35, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0082, 0x0000,}, // RAM Address End - Partial Display 1 (R82h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0083, 0x0000,}, // Display Position - Partial Display 2 (R83h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0084, 0x0000,}, // RAM Address Start - Partial Display 2 (R84h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0085, 0x0000,}, // RAM Address End - Partial Display 2 (R85h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0090, 0x0010,}, // Panel Interface Control 1 (R90h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0092, 0x0000,}, // Panel Interface Control 2 (R92h) Page 37, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0093, 0x0103,}, // Panel Interface control 3 (R93h) Page 38, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0095, 0x0210,}, // Panel Interface control 4 (R95h) Page 38, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0097, 0x0000,}, // Panel Interface Control 5 (R97h) Page 40, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0098, 0x0000,}, // Panel Interface Control 6 (R98h) Page 41, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0007, 0x0173,}, // Display Control (R07h) Page 16, SPFD5408B Datasheet + {LCD_STEP_DONE, 0, 0}, +}; + +const struct ubicom32lcd_panel cfaf240320ktts_0 = { + .desc = "CFAF240320KTTS", + .init_seq = cfaf240320ktts_init_0, + .horz_reg = 0x20, + .vert_reg = 0x21, + .gram_reg = 0x22, + .xres = 240, + .yres = 320, + .stride = 240, + .id = 0x5408, +}; +#endif + +#ifdef CONFIG_LCD_UBICOM32_CFAF240320KTTS_180 +static const struct ubicom32lcd_step cfaf240320ktts_init_180[] = { + {LCD_STEP_CMD_DATA, 0x0001, 0x0000,}, // Driver Output Control Register (R01h) Page 14, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0002, 0x0700,}, // LCD Driving Waveform Control (R02h) Page 15, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0003, 0x5000,}, // Entry Mode (R03h) 180 degrees + {LCD_STEP_CMD_DATA, 0x0004, 0x0000,}, // Scaling Control register (R04h) Page 16, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0008, 0x0207,}, // Display Control 2 (R08h) Page 17, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0009, 0x0000,}, // Display Control 3 (R09h) Page 18, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x000A, 0x0000,}, // Frame Cycle Control (R0Ah) Page 19, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x000C, 0x0000,}, // External Display Interface Control 1 (R0Ch) Page 20, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x000D, 0x0000,}, // Frame Maker Position (R0Dh) Page 21, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x000F, 0x0000,}, // External Display Interface Control 2 (R0Fh) Page 21, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0010, 0x0000,}, // Power Control 1 (R10h) Page 22, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h) Page 23, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0012, 0x0000,}, // Power Control 3 (R12h) Page 24, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0013, 0x0000,}, // Power Control 4 (R13h) Page 25, SPFD5408B Datasheet + {LCD_STEP_SLEEP, 0, 200}, + {LCD_STEP_CMD_DATA, 0x0007, 0x0101,}, // Display Control (R07h) Page 16, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0010, 0x12B0,}, // Power Control 1 (R10h) Page 22, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h) Page 23, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0012, 0x01BB,}, // Power Control 3 (R12h) Page 24, SPFD5408B Datasheet + {LCD_STEP_SLEEP, 0, 50}, + {LCD_STEP_CMD_DATA, 0x0013, 0x1300,}, // Power Control 4 (R13h) Page 25, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0029, 0x0010,}, // NVM read data 2 (R29h) Page 30, SPFD5408B Datasheet + {LCD_STEP_SLEEP, 0, 50}, + {LCD_STEP_CMD_DATA, 0x0030, 0x000A,}, // Gamma Control 1 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0031, 0x1326,}, // Gamma Control 2 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0032, 0x0A29,}, // Gamma Control 3 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0033, 0x290A,}, // Gamma Control 4 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0034, 0x2613,}, // Gamma Control 5 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0035, 0x0A0A,}, // Gamma Control 6 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0036, 0x1E03,}, // Gamma Control 7 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0037, 0x031E,}, // Gamma Control 8 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0038, 0x0706,}, // Gamma Control 9 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0039, 0x0303,}, // Gamma Control 10 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003A, 0x0E04,}, // Gamma Control 11 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003B, 0x0E01,}, // Gamma Control 12 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003C, 0x010E,}, // Gamma Control 13 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003D, 0x040E,}, // Gamma Control 14 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003E, 0x0303,}, // Gamma Control 15 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x003F, 0x0607,}, // Gamma Control 16 Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0050, 0x0000,}, // Window Horizontal RAM Address Start (R50h) Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0051, 0x00EF,}, // Window Horizontal RAM Address End (R51h) Page 32, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0052, 0x0000,}, // Window Vertical RAM Address Start (R52h) Page 33, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0053, 0x013F,}, // Window Vertical RAM Address End (R53h) Page 33, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0060, 0x2700,}, // Driver Output Control (R60h) Page 33, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0061, 0x0001,}, // Driver Output Control (R61h) Page 35, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x006A, 0x0000,}, // Vertical Scroll Control (R6Ah) Page 35, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0080, 0x0000,}, // Display Position - Partial Display 1 (R80h) Page 35, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0081, 0x0000,}, // RAM Address Start - Partial Display 1 (R81h) Page 35, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0082, 0x0000,}, // RAM Address End - Partial Display 1 (R82h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0083, 0x0000,}, // Display Position - Partial Display 2 (R83h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0084, 0x0000,}, // RAM Address Start - Partial Display 2 (R84h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0085, 0x0000,}, // RAM Address End - Partial Display 2 (R85h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0090, 0x0010,}, // Panel Interface Control 1 (R90h) Page 36, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0092, 0x0000,}, // Panel Interface Control 2 (R92h) Page 37, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0093, 0x0103,}, // Panel Interface control 3 (R93h) Page 38, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0095, 0x0210,}, // Panel Interface control 4 (R95h) Page 38, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0097, 0x0000,}, // Panel Interface Control 5 (R97h) Page 40, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0098, 0x0000,}, // Panel Interface Control 6 (R98h) Page 41, SPFD5408B Datasheet + {LCD_STEP_CMD_DATA, 0x0007, 0x0173,}, // Display Control (R07h) Page 16, SPFD5408B Datasheet + {LCD_STEP_DONE, 0, 0}, +}; + +const struct ubicom32lcd_panel cfaf240320ktts_180 = { + .desc = "CFAF240320KTTS 180", + .init_seq = cfaf240320ktts_init_180, + .horz_reg = 0x20, + .vert_reg = 0x21, + .gram_reg = 0x22, + .xres = 240, + .yres = 320, + .stride = 240, + .id = 0x5408, +}; +#endif + +#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_P +static const struct ubicom32lcd_step tft2n0369ep_init[] = { + {LCD_STEP_CMD_DATA, 0x0028, 0x0006}, + {LCD_STEP_CMD_DATA, 0x0000, 0x0001}, + {LCD_STEP_SLEEP, 0, 15}, + {LCD_STEP_CMD_DATA, 0x002B, 0x9532}, + {LCD_STEP_CMD_DATA, 0x0003, 0xAAAC}, + {LCD_STEP_CMD_DATA, 0x000C, 0x0002}, + {LCD_STEP_CMD_DATA, 0x000D, 0x000A}, + {LCD_STEP_CMD_DATA, 0x000E, 0x2C00}, + {LCD_STEP_CMD_DATA, 0x001E, 0x00AA}, + {LCD_STEP_CMD_DATA, 0x0025, 0x8000}, + {LCD_STEP_SLEEP, 0, 15}, + {LCD_STEP_CMD_DATA, 0x0001, 0x2B3F}, + {LCD_STEP_CMD_DATA, 0x0002, 0x0600}, + {LCD_STEP_CMD_DATA, 0x0010, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0011, 0x6030}, + {LCD_STEP_SLEEP, 0, 20}, + {LCD_STEP_CMD_DATA, 0x0005, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0006, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0016, 0xEF1C}, + {LCD_STEP_CMD_DATA, 0x0017, 0x0003}, + {LCD_STEP_CMD_DATA, 0x0007, 0x0233}, + {LCD_STEP_CMD_DATA, 0x000B, 0x5312}, + {LCD_STEP_CMD_DATA, 0x000F, 0x0000}, + {LCD_STEP_SLEEP, 0, 20}, + {LCD_STEP_CMD_DATA, 0x0041, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0042, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0048, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0049, 0x013F}, + {LCD_STEP_CMD_DATA, 0x0044, 0xEF00}, + {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0046, 0x013F}, + {LCD_STEP_CMD_DATA, 0x004A, 0x0000}, + {LCD_STEP_CMD_DATA, 0x004B, 0x0000}, + {LCD_STEP_SLEEP, 0, 20}, + {LCD_STEP_CMD_DATA, 0x0030, 0x0707}, + {LCD_STEP_CMD_DATA, 0x0031, 0x0704}, + {LCD_STEP_CMD_DATA, 0x0032, 0x0204}, + {LCD_STEP_CMD_DATA, 0x0033, 0x0201}, + {LCD_STEP_CMD_DATA, 0x0034, 0x0203}, + {LCD_STEP_CMD_DATA, 0x0035, 0x0204}, + {LCD_STEP_CMD_DATA, 0x0036, 0x0204}, + {LCD_STEP_CMD_DATA, 0x0037, 0x0502}, + {LCD_STEP_CMD_DATA, 0x003A, 0x0302}, + {LCD_STEP_CMD_DATA, 0x003B, 0x0500}, + {LCD_STEP_SLEEP, 0, 20}, + {LCD_STEP_CMD_DATA, 0x0044, 239 << 8 | 0}, + {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0046, 319}, + {LCD_STEP_DONE, 0, 0}, +}; + +const struct ubicom32lcd_panel tft2n0369ep = { + .desc = "TFT2N0369E-Portrait", + .init_seq = tft2n0369ep_init, + .horz_reg = 0x4e, + .vert_reg = 0x4f, + .gram_reg = 0x22, + .xres = 240, + .yres = 320, + .stride = 240, + .id = 0x8989, +}; +#endif + +#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_L +static const struct ubicom32lcd_step tft2n0369e_init[] = { + {LCD_STEP_CMD_DATA, 0x0028, 0x0006}, + {LCD_STEP_CMD_DATA, 0x0000, 0x0001}, + {LCD_STEP_SLEEP, 0, 15}, + {LCD_STEP_CMD_DATA, 0x002B, 0x9532}, + {LCD_STEP_CMD_DATA, 0x0003, 0xAAAC}, + {LCD_STEP_CMD_DATA, 0x000C, 0x0002}, + {LCD_STEP_CMD_DATA, 0x000D, 0x000A}, + {LCD_STEP_CMD_DATA, 0x000E, 0x2C00}, + {LCD_STEP_CMD_DATA, 0x001E, 0x00AA}, + {LCD_STEP_CMD_DATA, 0x0025, 0x8000}, + {LCD_STEP_SLEEP, 0, 15}, + {LCD_STEP_CMD_DATA, 0x0001, 0x2B3F}, + {LCD_STEP_CMD_DATA, 0x0002, 0x0600}, + {LCD_STEP_CMD_DATA, 0x0010, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0011, 0x60A8}, + {LCD_STEP_SLEEP, 0, 20}, + {LCD_STEP_CMD_DATA, 0x0005, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0006, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0016, 0xEF1C}, + {LCD_STEP_CMD_DATA, 0x0017, 0x0003}, + {LCD_STEP_CMD_DATA, 0x0007, 0x0233}, + {LCD_STEP_CMD_DATA, 0x000B, 0x5312}, + {LCD_STEP_CMD_DATA, 0x000F, 0x0000}, + {LCD_STEP_SLEEP, 0, 20}, + {LCD_STEP_CMD_DATA, 0x0041, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0042, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0048, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0049, 0x013F}, + {LCD_STEP_CMD_DATA, 0x0044, 0xEF00}, + {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0046, 0x013F}, + {LCD_STEP_CMD_DATA, 0x004A, 0x0000}, + {LCD_STEP_CMD_DATA, 0x004B, 0x0000}, + {LCD_STEP_SLEEP, 0, 20}, + {LCD_STEP_CMD_DATA, 0x0030, 0x0707}, + {LCD_STEP_CMD_DATA, 0x0031, 0x0704}, + {LCD_STEP_CMD_DATA, 0x0032, 0x0204}, + {LCD_STEP_CMD_DATA, 0x0033, 0x0201}, + {LCD_STEP_CMD_DATA, 0x0034, 0x0203}, + {LCD_STEP_CMD_DATA, 0x0035, 0x0204}, + {LCD_STEP_CMD_DATA, 0x0036, 0x0204}, + {LCD_STEP_CMD_DATA, 0x0037, 0x0502}, + {LCD_STEP_CMD_DATA, 0x003A, 0x0302}, + {LCD_STEP_CMD_DATA, 0x003B, 0x0500}, + {LCD_STEP_SLEEP, 0, 20}, + {LCD_STEP_CMD_DATA, 0x0044, 239 << 8 | 0}, + {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0046, 319}, + {LCD_STEP_DONE, 0, 0}, +}; + +const struct ubicom32lcd_panel tft2n0369e = { + .desc = "TFT2N0369E-Landscape", + .init_seq = tft2n0369e_init, + .horz_reg = 0x4e, + .vert_reg = 0x4f, + .gram_reg = 0x22, + .xres = 320, + .yres = 240, + .stride = 320, + .id = 0x8989, +}; +#endif + +#ifdef CONFIG_LCD_UBICOM32_CFAF240400D +static const struct ubicom32lcd_step cfaf240400d_init[] = { + {LCD_STEP_CMD_DATA, 0x0606, 0x0000}, // Pin Control (R606h) // Page 41 of SPFD5420A Datasheet + {LCD_STEP_SLEEP, 0, 50}, + {LCD_STEP_CMD_DATA, 0x0007, 0x0001}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet + {LCD_STEP_SLEEP, 0, 50}, + {LCD_STEP_CMD_DATA, 0x0110, 0x0001}, // Power Control 6(R110h) // Page 30 of SPFD5420A Datasheet + {LCD_STEP_SLEEP, 0, 50}, + {LCD_STEP_CMD_DATA, 0x0100, 0x17B0}, // Power Control 1 (R100h) // Page 26 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0101, 0x0147}, // Power Control 2 (R101h) // Page 27 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0102, 0x019D}, // Power Control 3 (R102h) // Page 28 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0103, 0x3600}, // Power Control 4 (R103h) // Page 29 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0281, 0x0010}, // NVM read data 2 (R281h) // Page 34 of SPFD5420A Datasheet + {LCD_STEP_SLEEP, 0, 50}, + {LCD_STEP_CMD_DATA, 0x0102, 0x01BD}, // Power Control 3 (R102h) // Page 28 of SPFD5420A Datasheet + {LCD_STEP_SLEEP, 0, 50}, + + //--------------- Power control 1~6 ---------------// + {LCD_STEP_CMD_DATA, 0x0100, 0x16B0}, // Power Control 1 (R100h) // Page 26 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0101, 0x0147}, // Power Control 2 (R101h) // Page 27 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0102, 0x01BD}, // Power Control 3 (R102h) // Page 28 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0103, 0x2d00}, // Power Control 4 (R103h) // Page 29 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0107, 0x0000}, // Power Control 5 (R107h) // Page 30 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0110, 0x0001}, // Power Control 6(R110h) // Page 30 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0280, 0x0000}, // NVM read data 1 (R280h) // Page 33 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0281, 0x0006}, // NVM read data 2 (R281h) // Page 34 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0282, 0x0000}, // NVM read data 3 (R282h) // Page 34 of SPFD5420A Datasheet + + //------- Gamma 2.2 control (R300h to R30Fh) ------// + {LCD_STEP_CMD_DATA, 0x0300, 0x0101}, + {LCD_STEP_CMD_DATA, 0x0301, 0x0b27}, + {LCD_STEP_CMD_DATA, 0x0302, 0x132a}, + {LCD_STEP_CMD_DATA, 0x0303, 0x2a13}, + {LCD_STEP_CMD_DATA, 0x0304, 0x270b}, + {LCD_STEP_CMD_DATA, 0x0305, 0x0101}, + {LCD_STEP_CMD_DATA, 0x0306, 0x1205}, + {LCD_STEP_CMD_DATA, 0x0307, 0x0512}, + {LCD_STEP_CMD_DATA, 0x0308, 0x0005}, + {LCD_STEP_CMD_DATA, 0x0309, 0x0003}, + {LCD_STEP_CMD_DATA, 0x030A, 0x0f04}, + {LCD_STEP_CMD_DATA, 0x030B, 0x0f00}, + {LCD_STEP_CMD_DATA, 0x030C, 0x000f}, + {LCD_STEP_CMD_DATA, 0x030D, 0x040f}, + {LCD_STEP_CMD_DATA, 0x030E, 0x0300}, + {LCD_STEP_CMD_DATA, 0x030F, 0x0500}, + + {LCD_STEP_CMD_DATA, 0x0400, 0x3500}, // Base Image Number of Line (R400h) // Page 36 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0401, 0x0001}, // Base Image Display Control (R401h) // Page 39 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0404, 0x0000}, // Based Image Vertical Scroll Control (R404h) // Page 40 of SPFD5420A Datasheet + + //--------------- Normal set ---------------// + {LCD_STEP_CMD_DATA, 0x0000, 0x0000}, // ID Read Register (R000h) // Page 13 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0001, 0x0100}, // Driver Output Control Register (R001h) // Page 14 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0002, 0x0100}, // LCD Driving Waveform Control (R002h) // Page 14 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0003, 0x1030}, // Entry Mode (R003h) // Page 15 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0006, 0x0000}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0008, 0x0808}, // Display Control 2 (R008h) // Page 17 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0009, 0x0001}, // Display Control 3 (R009h) // Page 18 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x000B, 0x0010}, // Low Power Control (R00Bh) // Page 19 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x000C, 0x0000}, // External Display Interface Control 1 (R00Ch) // Page 19 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x000F, 0x0000}, // External Display Interface Control 2 (R00Fh) // Page 20 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0007, 0x0001}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet + + //--------------- Panel interface control 1~6 ---------------// + {LCD_STEP_CMD_DATA, 0x0010, 0x0012}, // Panel Interface Control 1 (R010h) // Page 20 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0011, 0x0202}, // Panel Interface Control 2 (R011h) // Page 21 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0012, 0x0300}, // Panel Interface control 3 (R012h) // Page 22 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0020, 0x021E}, // Panel Interface control 4 (R020h) // Page 22 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0021, 0x0202}, // Panel Interface Control 5 (021Rh) // Page 24 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0022, 0x0100}, // Panel Interface Control 6 (R022h) // Page 25 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0090, 0x8000}, // Frame Marker Control (R090h) // Page 25 of SPFD5420A Datasheet + + //--------------- Partial display ---------------// + {LCD_STEP_CMD_DATA, 0x0210, 0x0000}, // Window Horizontal RAM Address Start (R210h) // Page 35 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0211, 0x00EF}, // Window Horziontal RAM Address End (R211h) // Page 35 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0212, 0x0000}, // Window Vertical RAM Address Start (R212h) // Page 35 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0213, 0x018F}, // Window Vertical RAM Address End (R213h) // Page 35 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0500, 0x0000}, // Display Position - Partial Display 1 (R500h) // Page 40 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0501, 0x0000}, // RAM Address Start - Partial Display 1 (R501h)// Page 40 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0502, 0x0000}, // RAM Address End - Partail Display 1 (R502h) // Page 40 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0503, 0x0000}, // Display Position - Partial Display 2 (R503h) // Page 40 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0504, 0x0000}, // RAM Address Start . Partial Display 2 (R504h)// Page 41 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0505, 0x0000}, // RAM Address End . Partial Display 2 (R505h) // Page 41 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0606, 0x0000}, // Pin Control (R606h) // Page 41 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x06F0, 0x0000}, // NVM Access Control (R6F0h) // Page 41 of SPFD5420A Datasheet + {LCD_STEP_CMD_DATA, 0x0007, 0x0173}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet + {LCD_STEP_SLEEP, 0, 50}, + {LCD_STEP_CMD_DATA, 0x0007, 0x0171}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet + {LCD_STEP_SLEEP, 0, 10}, + {LCD_STEP_CMD_DATA, 0x0007, 0x0173}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet + {LCD_STEP_DONE, 0, 0}, +}; + +const struct ubicom32lcd_panel cfaf240400d = { + .desc = "CFAF240400D", + .init_seq = cfaf240400d_init, + .horz_reg = 0x0200, + .vert_reg = 0x0201, + .gram_reg = 0x0202, + .xres = 240, + .yres = 400, + .stride = 240, + .id = 0x5420, +}; +#endif + +#ifdef CONFIG_LCD_UBICOM32_CFAF240400F +static const struct ubicom32lcd_step cfaf320240f_init[] = { + {LCD_STEP_CMD_DATA, 0x0028, 0x0006}, // VCOM OTP Page 55-56 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0000, 0x0001}, // start Oscillator Page 36 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0010, 0x0000}, // Sleep mode Page 49 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0001, 0x32EF}, // Driver Output Control Page 36-39 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0002, 0x0600}, // LCD Driving Waveform Control Page 40-42 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0003, 0x6A38}, // Power Control 1 Page 43-44 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0011, 0x6870}, // Entry Mode Page 50-52 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0X000F, 0x0000}, // Gate Scan Position Page 49 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0X000B, 0x5308}, // Frame Cycle Control Page 45 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x000C, 0x0003}, // Power Control 2 Page 47 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x000D, 0x000A}, // Power Control 3 Page 48 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x000E, 0x2E00}, // Power Control 4 Page 48 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x001E, 0x00BE}, // Power Control 5 Page 53 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0025, 0x8000}, // Frame Frequency Control Page 53 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0026, 0x7800}, // Analog setting Page 54 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x004E, 0x0000}, // Ram Address Set Page 58 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x004F, 0x0000}, // Ram Address Set Page 58 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0012, 0x08D9}, // Sleep mode Page 49 of SSD2119 datasheet + + // Gamma Control (R30h to R3Bh) -- Page 56 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0030, 0x0000}, + {LCD_STEP_CMD_DATA, 0x0031, 0x0104}, + {LCD_STEP_CMD_DATA, 0x0032, 0x0100}, + {LCD_STEP_CMD_DATA, 0x0033, 0x0305}, + {LCD_STEP_CMD_DATA, 0x0034, 0x0505}, + {LCD_STEP_CMD_DATA, 0x0035, 0x0305}, + {LCD_STEP_CMD_DATA, 0x0036, 0x0707}, + {LCD_STEP_CMD_DATA, 0x0037, 0x0300}, + {LCD_STEP_CMD_DATA, 0x003A, 0x1200}, + {LCD_STEP_CMD_DATA, 0x003B, 0x0800}, + + {LCD_STEP_CMD_DATA, 0x0007, 0x0033}, // Display Control Page 45 of SSD2119 datasheet + + {LCD_STEP_CMD_DATA, 0x0044, 0xEF00}, // Vertical RAM address position Page 57 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, // Horizontal RAM address position Page 57 of SSD2119 datasheet + {LCD_STEP_CMD_DATA, 0x0046, 0x013F}, // Horizontal RAM address position Page 57 of SSD2119 datasheet + + {LCD_STEP_SLEEP, 0, 150}, + + {LCD_STEP_DONE, 0, 0}, +}; + +const struct ubicom32lcd_panel cfaf320240f = { + .desc = "CFAF320240F", + .init_seq = cfaf320240f_init, + .horz_reg = 0x4e, + .vert_reg = 0x4f, + .gram_reg = 0x22, + .xres = 320, + .yres = 240, + .stride = 320, + .id = 0x9919, +}; +#endif + +const struct ubicom32lcd_panel *ubicom32lcd_panels[] = { +#ifdef CONFIG_LCD_UBICOM32_CFAF240400KTTS_180 + &cfaf240320ktts_180, +#endif +#ifdef CONFIG_LCD_UBICOM32_CFAF240400KTTS + &cfaf240320ktts_0, +#endif +#ifdef CONFIG_LCD_UBICOM32_CFAF240400D + &cfaf240400d, +#endif +#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_P + &tft2n0369ep, +#endif +#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_L + &tft2n0369e, +#endif +#ifdef CONFIG_LCD_UBICOM32_CFAF240400F + &cfaf320240f, +#endif + NULL, +}; + +#endif diff --git a/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcdpower.c b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcdpower.c new file mode 100644 index 000000000..6aeed43bc --- /dev/null +++ b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcdpower.c @@ -0,0 +1,194 @@ +/* + * drivers/video/backlight/ubicom32lcdpowerpower.c + * LCD power driver for the Ubicom32 platform + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "ubicom32lcdpower" + +struct ubicom32lcdpower_data { + /* + * Pointer to the platform data structure. Keep this around since we need values + * from it to set the backlight intensity. + */ + const struct ubicom32lcdpower_platform_data *pdata; + + /* + * LCD device, we have to save this for use when we remove ourselves. + */ + struct lcd_device *lcddev; +}; + +/* + * ubicom32lcdpower_set_power + */ +static int ubicom32lcdpower_set_power(struct lcd_device *ld, int power) +{ + struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld); + if (power == FB_BLANK_UNBLANK) { + gpio_direction_output(ud->pdata->vgh_gpio, ud->pdata->vgh_polarity); + return 0; + } + + gpio_direction_output(ud->pdata->vgh_gpio, !ud->pdata->vgh_polarity); + return 0; +} + +/* + * ubicom32lcdpower_get_power + */ +static int ubicom32lcdpower_get_power(struct lcd_device *ld) +{ + struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld); + int vgh = gpio_get_value(ud->pdata->vgh_gpio); + if ((vgh && ud->pdata->vgh_polarity) || (!vgh && !ud->pdata->vgh_polarity)) { + return 1; + } + + return 0; +} + +static struct lcd_ops ubicom32lcdpower_ops = { + .get_power = ubicom32lcdpower_get_power, + .set_power = ubicom32lcdpower_set_power, +}; + +/* + * ubicom32lcdpower_probe + */ +static int ubicom32lcdpower_probe(struct platform_device *pdev) +{ + const struct ubicom32lcdpower_platform_data *pdata = pdev->dev.platform_data; + struct ubicom32lcdpower_data *ud; + struct lcd_device *lcddev; + int retval; + + /* + * Check to see if we have any platform data, if we don't have a LCD to control + */ + if (!pdata) { + return -ENODEV; + } + + /* + * Allocate our private data + */ + ud = kzalloc(sizeof(struct ubicom32lcdpower_data), GFP_KERNEL); + if (!ud) { + return -ENOMEM; + } + + ud->pdata = pdata; + + /* + * Request our GPIOs + */ + retval = gpio_request(pdata->vgh_gpio, "vgh"); + if (retval) { + dev_err(&pdev->dev, "Failed to allocate vgh GPIO\n"); + goto fail_gpio; + } + + /* + * Register our lcd device + */ + lcddev = lcd_device_register(DRIVER_NAME, &pdev->dev, ud, &ubicom32lcdpower_ops); + if (IS_ERR(lcddev)) { + retval = PTR_ERR(lcddev); + goto fail; + } + + ud->lcddev = lcddev; + platform_set_drvdata(pdev, ud); + + ubicom32lcdpower_set_power(lcddev, FB_BLANK_UNBLANK); + + printk(KERN_INFO DRIVER_NAME ": LCD driver started\n"); + + return 0; + +fail: + gpio_free(pdata->vgh_gpio); + +fail_gpio: + platform_set_drvdata(pdev, NULL); + kfree(ud); + return retval; +} + +/* + * ubicom32lcdpower_remove + */ +static int __exit ubicom32lcdpower_remove(struct platform_device *pdev) +{ + struct ubicom32lcdpower_data *ud = platform_get_drvdata(pdev); + + lcd_device_unregister(ud->lcddev); + platform_set_drvdata(pdev, NULL); + kfree(ud); + + return 0; +} + +static struct platform_driver ubicom32lcdpower_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + + .remove = __exit_p(ubicom32lcdpower_remove), +}; + +/* + * ubicom32lcdpower_init + */ +static int __init ubicom32lcdpower_init(void) +{ + return platform_driver_probe(&ubicom32lcdpower_driver, ubicom32lcdpower_probe); +} +module_init(ubicom32lcdpower_init); + +/* + * ubicom32lcdpower_exit + */ +static void __exit ubicom32lcdpower_exit(void) +{ + platform_driver_unregister(&ubicom32lcdpower_driver); +} +module_exit(ubicom32lcdpower_exit); + +MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); +MODULE_DESCRIPTION("Ubicom32 lcd power driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/drivers/video/ubicom32fb.c b/target/linux/ubicom32/files/drivers/video/ubicom32fb.c new file mode 100644 index 000000000..4193560f7 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/video/ubicom32fb.c @@ -0,0 +1,779 @@ +/* + * drivers/video/ubicom32fb.c + * Ubicom32 frame buffer driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +/* + * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by + * Geert Uytterhoeven. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DRIVER_NAME "ubicom32fb" +#define DRIVER_DESCRIPTION "Ubicom32 frame buffer driver" + +#define PALETTE_ENTRIES_NO 16 + +/* + * Option variables + * + * vram_size: VRAM size in kilobytes, subject to alignment + */ +static int vram_size = 0; +module_param(vram_size, int, 0); +MODULE_PARM_DESC(vram, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment"); +static int init_value = 0; +module_param(init_value, int, 0); +MODULE_PARM_DESC(init, "Initial value of the framebuffer (16-bit number)."); + +/* + * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in. + */ +static struct fb_fix_screeninfo ubicom32fb_fix = { + .id = "Ubicom32", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .accel = FB_ACCEL_UBICOM32, +}; + +/* + * Filled in at probe time when we find out what the hardware supports + */ +static struct fb_var_screeninfo ubicom32fb_var; + +/* + * Private data structure + */ +struct ubicom32fb_drvdata { + struct fb_info *fbinfo; + bool cmap_alloc; + + /* + * The address of the framebuffer in memory + */ + void *fb; + void *fb_aligned; + + /* + * Total size of vram including alignment allowance + */ + u32 total_vram_size; + + /* + * Interrupt to set when changing registers + */ + u32 vp_int; + + /* + * Optional: Interrupt used by TIO to signal us + */ + u32 rx_int; + + /* + * Base address of the regs for VDC_TIO + */ + volatile struct vdc_tio_vp_regs *regs; + + /* + * non-zero if we are in yuv mode + */ + u8_t is_yuv; + + /* + * Fake palette of 16 colors + */ + u32 pseudo_palette[PALETTE_ENTRIES_NO]; + + /* + * Wait queue and lock used to block when we need to wait + * for something to happen. + */ + wait_queue_head_t waitq; + struct mutex lock; + +}; + +/* + * ubicom32fb_set_next_frame + * Sets the next frame buffer to display + * + * if sync is TRUE then this function will block until the hardware + * acknowledges the change + */ +static inline void ubicom32fb_set_next_frame(struct ubicom32fb_drvdata *ud, void *fb, u8_t sync) +{ + ud->regs->next_frame_flags = ud->is_yuv ? VDCTIO_NEXT_FRAME_FLAG_YUV : 0; + ud->regs->next_frame = (void *)((u32_t)fb | 1); + + /* + * If we have interrupts, then we can wait on it + */ + if (ud->rx_int != -1) { + DEFINE_WAIT(wait); + unsigned long flags; + + spin_lock_irqsave(&ud->lock, flags); + prepare_to_wait(&ud->waitq, &wait, TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&ud->lock, flags); + schedule(); + finish_wait(&ud->waitq, &wait); + return; + } + + /* + * No interrupt, we will just spin here + */ + while (sync && ((u32_t)ud->regs->next_frame & 1)); +} + +/* + * ubicom32fb_send_command + * Sends a command/data pair to the VDC + */ +static inline void ubicom32fb_send_command(struct ubicom32fb_drvdata *ud, u16 command, u8_t block) +{ + ud->regs->command = command; + ubicom32_set_interrupt(ud->vp_int); + while (block && ud->regs->command); +} + +/* + * ubicom32fb_ioctl + * Handles any ioctls sent to us + */ +static int ubicom32fb_ioctl(struct fb_info *fbi, unsigned int cmd, + unsigned long arg) +{ + struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)fbi->par; + void __user *argp = (void __user *)arg; + int retval = -EFAULT; + + switch (cmd) { + case UBICOM32FB_IOCTL_SET_NEXT_FRAME_SYNC: + // check alignment, return -EINVAL if necessary + ubicom32fb_set_next_frame(ud, argp, 1); + retval = 0; + break; + + case UBICOM32FB_IOCTL_SET_NEXT_FRAME: + // check alignment, return -EINVAL if necessary + ubicom32fb_set_next_frame(ud, argp, 0); + retval = 0; + break; + + case UBICOM32FB_IOCTL_SET_MODE: + if (!(ud->regs->caps & VDCTIO_CAPS_SUPPORTS_SCALING)) { + break; + } else { + struct ubicom32fb_mode mode; + volatile struct vdc_tio_vp_regs *regs = ud->regs; + u32_t flags = 0; + + if (copy_from_user(&mode, argp, sizeof(mode))) { + break; + } + + regs->x_in = mode.width; + regs->y_in = mode.height; + regs->x_out = regs->xres; + regs->y_out = regs->yres; + if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_SCAN_ORDER) { + flags |= VDCTIO_SCALE_FLAG_YUV_SCAN_ORDER; + } + if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_BLOCK_ORDER) { + flags |= VDCTIO_SCALE_FLAG_YUV_BLOCK_ORDER; + } + ud->is_yuv = mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV; + if (ud->is_yuv) { + flags |= VDCTIO_SCALE_FLAG_YUV; + } + if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_16_255) { + flags |= VDCTIO_SCALE_FLAG_VRANGE_16_255; + } + if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_0_255) { + flags |= VDCTIO_SCALE_FLAG_VRANGE_0_255; + } + if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VSUB) { + flags |= VDCTIO_SCALE_FLAG_VSUB; + } + if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_2_1) { + flags |= VDCTIO_SCALE_FLAG_HSUB_2_1; + } + if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_1_1) { + flags |= VDCTIO_SCALE_FLAG_HSUB_1_1; + } + if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_SCALE_ENABLE) { + flags |= VDCTIO_SCALE_FLAG_ENABLE; + } + if (mode.next_frame) { + flags |= VDCTIO_SCALE_FLAG_SET_FRAME_BUFFER; + regs->next_frame = mode.next_frame; + } + + regs->scale_flags = flags; + ubicom32fb_send_command(ud, VDCTIO_COMMAND_SET_SCALE_MODE, 1); + retval = 0; + break; + } + + default: + retval = -ENOIOCTLCMD; + break; + } + + return retval; +} + +/* + * ubicom32fb_interrupt + * Called by the OS when the TIO has set the rx_int + */ +static irqreturn_t ubicom32fb_interrupt(int vec, void *appdata) +{ + struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)appdata; + + spin_lock(&ud->lock); + if (waitqueue_active(&ud->waitq)) { + wake_up(&ud->waitq); + } + spin_unlock(&ud->lock); + + return IRQ_HANDLED; +} + +/* + * ubicom32fb_pan_display + * Pans the display to a given location. Supports only y direction panning. + */ +static int ubicom32fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) +{ + struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)fbi->par; + void *new_addr; + + /* + * Get the last y line that would be displayed. Since we don't support YWRAP, + * it must be less than our virtual y size. + */ + u32 lasty = var->yoffset + var->yres; + if (lasty > fbi->var.yres_virtual) { + /* + * We would fall off the end of our frame buffer if we panned here. + */ + return -EINVAL; + } + + if (var->xoffset) { + /* + * We don't support panning in the x direction + */ + return -EINVAL; + } + + /* + * Everything looks sane, go ahead and pan + * + * We have to calculate a new address for the VDC to look at + */ + new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length); + + /* + * Send down the command. The buffer will switch at the next vertical blank + */ + ubicom32fb_set_next_frame(ud, (void *)new_addr, 0); + + return 0; +} + +/* + * ubicom32fb_setcolreg + * Sets a color in our virtual palette + */ +static int ubicom32fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi) +{ + u32 *palette = fbi->pseudo_palette; + + if (regno >= PALETTE_ENTRIES_NO) { + return -EINVAL; + } + + /* + * We only use 8 bits from each color + */ + red >>= 8; + green >>= 8; + blue >>= 8; + + /* + * Convert any grayscale values + */ + if (fbi->var.grayscale) { + u16 gray = red + green + blue; + gray += (gray >> 2) + (gray >> 3) - (gray >> 7); + gray >>= 2; + if (gray > 255) { + gray = 255; + } + red = gray; + blue = gray; + green = gray; + } + + palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) | + (blue << fbi->var.blue.offset); + + return 0; +} + +/* + * ubicom32fb_mmap + */ +static int ubicom32fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct ubicom32fb_drvdata *drvdata = (struct ubicom32fb_drvdata *)info->par; + + vma->vm_start = (unsigned long)(drvdata->fb_aligned); + + vma->vm_end = vma->vm_start + info->fix.smem_len; + + /* For those who don't understand how mmap works, go read + * Documentation/nommu-mmap.txt. + * For those that do, you will know that the VM_MAYSHARE flag + * must be set in the vma->vm_flags structure on noMMU + * Other flags can be set, and are documented in + * include/linux/mm.h + */ + + vma->vm_flags |= VM_MAYSHARE | VM_SHARED; + + return 0; +} + +/* + * ubicom32fb_blank + */ +static int ubicom32fb_blank(int blank_mode, struct fb_info *fbi) +{ + return 0; +#if 0 + struct ubicom32fb_drvdata *drvdata = to_ubicom32fb_drvdata(fbi); + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + /* turn on panel */ + ubicom32fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); + break; + + case FB_BLANK_NORMAL: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + /* turn off panel */ + ubicom32fb_out_be32(drvdata, REG_CTRL, 0); + default: + break; + + } + return 0; /* success */ +#endif +} + +static struct fb_ops ubicom32fb_ops = +{ + .owner = THIS_MODULE, + .fb_pan_display = ubicom32fb_pan_display, + .fb_setcolreg = ubicom32fb_setcolreg, + .fb_blank = ubicom32fb_blank, + .fb_mmap = ubicom32fb_mmap, + .fb_ioctl = ubicom32fb_ioctl, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +/* + * ubicom32fb_release + */ +static int ubicom32fb_release(struct device *dev) +{ + struct ubicom32fb_drvdata *ud = dev_get_drvdata(dev); + +#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) + //ubicom32fb_blank(VESA_POWERDOWN, &drvdata->info); +#endif + + unregister_framebuffer(ud->fbinfo); + + if (ud->cmap_alloc) { + fb_dealloc_cmap(&ud->fbinfo->cmap); + } + + if (ud->fb) { + kfree(ud->fb); + } + + if (ud->rx_int != -1) { + free_irq(ud->rx_int, ud); + } + + /* + * Turn off the display + */ + //ubicom32fb_out_be32(drvdata, REG_CTRL, 0); + //iounmap(drvdata->regs); + + framebuffer_release(ud->fbinfo); + dev_set_drvdata(dev, NULL); + + return 0; +} + +/* + * ubicom32fb_platform_probe + */ +static int __init ubicom32fb_platform_probe(struct platform_device *pdev) +{ + struct ubicom32fb_drvdata *ud; + struct resource *irq_resource_rx; + struct resource *irq_resource_tx; + struct resource *mem_resource; + struct fb_info *fbinfo; + int rc; + size_t fbsize; + struct device *dev = &pdev->dev; + int offset; + struct vdc_tio_vp_regs *regs; + + /* + * Get our resources + */ + irq_resource_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq_resource_tx) { + dev_err(dev, "No tx IRQ resource assigned\n"); + return -ENODEV; + } + + irq_resource_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!irq_resource_rx) { + dev_err(dev, "No rx IRQ resource assigned\n"); + return -ENODEV; + } + + mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_resource || !mem_resource->start) { + dev_err(dev, "No mem resource assigned\n"); + return -ENODEV; + } + regs = (struct vdc_tio_vp_regs *)mem_resource->start; + if (regs->version != VDCTIO_VP_VERSION) { + dev_err(dev, "VDCTIO is not compatible with this driver tio:%x drv:%x\n", + regs->version, VDCTIO_VP_VERSION); + return -ENODEV; + } + + /* + * This is the minimum VRAM size + */ + fbsize = regs->xres * regs->yres * (regs->bpp / 8); + if (!vram_size) { + vram_size = (fbsize + 1023) / 1024; + } else { + if (fbsize > (vram_size * 1024)) { + dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize); + return -ENOMEM; // should be ebadparam? + } + } + + /* + * Allocate the framebuffer instance + our private data + */ + fbinfo = framebuffer_alloc(sizeof(struct ubicom32fb_drvdata), &pdev->dev); + if (!fbinfo) { + dev_err(dev, "Not enough memory to allocate instance.\n"); + return -ENOMEM; + } + + /* + * Fill in our private data. + */ + ud = (struct ubicom32fb_drvdata *)fbinfo->par; + ud->fbinfo = fbinfo; + ud->regs = (struct vdc_tio_vp_regs *)(mem_resource->start); + dev_set_drvdata(dev, ud); + + ud->vp_int = irq_resource_tx->start; + + /* + * If we were provided an rx_irq then we need to init the appropriate + * queues, locks, and functions. + */ + ud->rx_int = -1; + if (irq_resource_rx->start != DEVTREE_IRQ_NONE) { + init_waitqueue_head(&ud->waitq); + mutex_init(&ud->lock); + if (request_irq(ud->rx_int, ubicom32fb_interrupt, IRQF_SHARED, "ubicom32fb_rx", ud)) { + dev_err(dev, "Couldn't request rx IRQ\n"); + rc = -ENOMEM; + goto fail; + } + ud->rx_int = irq_resource_rx->start; + } + + /* + * Allocate and align the requested amount of VRAM + */ + ud->total_vram_size = (vram_size * 1024) + regs->fb_align; + ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL); + if (ud->fb == NULL) { + dev_err(dev, "Couldn't allocate VRAM\n"); + rc = -ENOMEM; + goto fail; + } + + offset = (u32_t)ud->fb & (regs->fb_align - 1); + if (!offset) { + ud->fb_aligned = ud->fb; + } else { + offset = regs->fb_align - offset; + ud->fb_aligned = ud->fb + offset; + } + + /* + * Clear the entire frame buffer + */ + if (!init_value) { + memset(ud->fb_aligned, 0, vram_size * 1024); + } else { + unsigned short *p = ud->fb_aligned; + int i; + for (i = 0; i < ((vram_size * 1024) / sizeof(u16_t)); i++) { + *p++ = init_value; + } + } + + /* + * Fill in the fb_var_screeninfo structure + */ + memset(&ubicom32fb_var, 0, sizeof(ubicom32fb_var)); + ubicom32fb_var.bits_per_pixel = regs->bpp; + ubicom32fb_var.red.offset = regs->rshift; + ubicom32fb_var.green.offset = regs->gshift; + ubicom32fb_var.blue.offset = regs->bshift; + ubicom32fb_var.red.length = regs->rbits; + ubicom32fb_var.green.length = regs->gbits; + ubicom32fb_var.blue.length = regs->bbits; + ubicom32fb_var.activate = FB_ACTIVATE_NOW; + +#if 0 + /* + * Turn on the display + */ + ud->reg_ctrl_default = REG_CTRL_ENABLE; + if (regs->rotate_screen) + ud->reg_ctrl_default |= REG_CTRL_ROTATE; + ubicom32fb_out_be32(ud, REG_CTRL, ud->reg_ctrl_default); +#endif + + /* + * Fill in the fb_info structure + */ + ud->fbinfo->device = dev; + ud->fbinfo->screen_base = (void *)ud->fb_aligned; + ud->fbinfo->fbops = &ubicom32fb_ops; + ud->fbinfo->fix = ubicom32fb_fix; + ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned; + ud->fbinfo->fix.smem_len = vram_size * 1024; + ud->fbinfo->fix.line_length = regs->xres * (regs->bpp / 8); + ud->fbinfo->fix.mmio_start = (u32)regs; + ud->fbinfo->fix.mmio_len = sizeof(struct vdc_tio_vp_regs); + + /* + * We support panning in the y direction only + */ + ud->fbinfo->fix.xpanstep = 0; + ud->fbinfo->fix.ypanstep = 1; + + ud->fbinfo->pseudo_palette = ud->pseudo_palette; + ud->fbinfo->flags = FBINFO_DEFAULT; + ud->fbinfo->var = ubicom32fb_var; + ud->fbinfo->var.xres = regs->xres; + ud->fbinfo->var.yres = regs->yres; + + /* + * We cannot pan in the X direction, so xres_virtual is regs->xres + * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length + */ + ud->fbinfo->var.xres_virtual = regs->xres; + ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length; + + //ud->fbinfo->var.height = regs->height_mm; + //ud->fbinfo->var.width = regs->width_mm; + + /* + * Allocate a color map + */ + rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0); + if (rc) { + dev_err(dev, "Fail to allocate colormap (%d entries)\n", + PALETTE_ENTRIES_NO); + goto fail; + } + ud->cmap_alloc = true; + + /* + * Register new frame buffer + */ + rc = register_framebuffer(ud->fbinfo); + if (rc) { + dev_err(dev, "Could not register frame buffer\n"); + goto fail; + } + + /* + * Start up the VDC + */ + ud->regs->next_frame = ud->fb; + ubicom32fb_send_command(ud, VDCTIO_COMMAND_START, 0); + + /* + * Tell the log we are here + */ + dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u), regs=%p irqtx=%u irqrx=%u\n", + ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres, + ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual, ud->regs, + irq_resource_tx->start, irq_resource_rx->start); + + /* + * Success + */ + return 0; + +fail: + ubicom32fb_release(dev); + return rc; +} + +/* + * ubicom32fb_platform_remove + */ +static int ubicom32fb_platform_remove(struct platform_device *pdev) +{ + dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n"); + return ubicom32fb_release(&pdev->dev); +} + +static struct platform_driver ubicom32fb_platform_driver = { + .probe = ubicom32fb_platform_probe, + .remove = ubicom32fb_platform_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +#ifndef MODULE +/* + * ubicom32fb_setup + * Process kernel boot options + */ +static int __init ubicom32fb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) { + return 0; + } + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) { + continue; + } + + if (!strncmp(this_opt, "init_value=", 10)) { + init_value = simple_strtoul(this_opt + 11, NULL, 0); + continue; + } + + if (!strncmp(this_opt, "vram_size=", 10)) { + vram_size = simple_strtoul(this_opt + 10, NULL, 0); + continue; + } + } + return 0; +} +#endif /* MODULE */ + +/* + * ubicom32fb_init + */ +static int __devinit ubicom32fb_init(void) +{ +#ifndef MODULE + /* + * Get kernel boot options (in 'video=ubicom32fb:') + */ + char *option = NULL; + + if (fb_get_options(DRIVER_NAME, &option)) { + return -ENODEV; + } + ubicom32fb_setup(option); +#endif /* MODULE */ + + return platform_driver_register(&ubicom32fb_platform_driver); +} +module_init(ubicom32fb_init); + +/* + * ubicom32fb_exit + */ +static void __exit ubicom32fb_exit(void) +{ + platform_driver_unregister(&ubicom32fb_platform_driver); +} +module_exit(ubicom32fb_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); diff --git a/target/linux/ubicom32/files/drivers/video/ubicom32plio80.c b/target/linux/ubicom32/files/drivers/video/ubicom32plio80.c new file mode 100644 index 000000000..2e13fd707 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/video/ubicom32plio80.c @@ -0,0 +1,780 @@ +/* + * drivers/video/ubicom32plio80.c + * Ubicom32 80 bus PLIO buffer driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +/* + * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by + * Geert Uytterhoeven. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "ubicom32plio80" +#define DRIVER_DESCRIPTION "Ubicom32 80 bus PLIO frame buffer driver" + +#define PALETTE_ENTRIES_NO 16 + +/* + * Option variables + * + * vram_size: VRAM size in kilobytes, subject to alignment + */ +static int vram_size = 0; +module_param(vram_size, int, 0); +MODULE_PARM_DESC(vram_size, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment"); + +static int xres = 240; +module_param(xres, int, 0); +MODULE_PARM_DESC(xres, "x (horizontal) resolution"); + +static int yres = 320; +module_param(yres, int, 0); +MODULE_PARM_DESC(yres, "y (vertical) resolution"); + +static int bgr = 0; +module_param(bgr, int, 0); +MODULE_PARM_DESC(bgr, "display is BGR (Blue is MSB)"); + +#define BITS_PER_PIXEL 16 + +/* + * Buffer alignment, must not be 0 + */ +#define UBICOM32PLIO80_ALIGNMENT 4 + +/* + * PLIO FSM + * 16-bit data bus on port I + * CS on EXTCTL[6] + * WR on EXTCTL[4] + */ +static const plio_fctl_t plio_fctl = { + .fctl0 = { + .ptif_port_mode = PLIO_PORT_MODE_DI, + .ptif_portd_cfg = 0, + .ptif_porti_cfg = 3, + .edif_ds = 6, + .edif_cmp_mode = 1, + .ecif_extclk_ena = 0, // enable clock output on PD7 table 2.65/p111 says extctl[0]? + .icif_clk_src_sel = PLIO_CLK_IO, + }, + .fctl2 = { + .icif_eclk_div = 10, + .icif_iclk_div = 10, + }, + + }; + + static const plio_config_t plio_config = { + .pfsm = { + /* + * Table 12.63 + */ + .grpsel[0] = {1,1,1,1,1,1,1,1,1,1}, + + /* + * Table 12.66 Counter load value + */ + .cs_lut[0] = {0,0,0,0,0,0,0,0}, + + /* + * Table 2.75 PLIO PFSM Configuration Registers + */ + // 3 2 1 0 + .extctl_o_lut[0] = {0x3f, 0x2f, 0x3f, 0x3f}, + // 7 6 5 4 + .extctl_o_lut[1] = {0x3f, 0x3f, 0x3f, 0x2f}, + }, + .edif = { + .odr_oe = 0xffff, + }, + .ecif = { + .output_ena = (1 << 6) | (1 << 4), + }, +}; + +static const u32_t ubicom32plio80_plio_fsm[] = { + // 0-F + 0x00070007, 0x00070007, + 0x00070007, 0x00070007, + 0x00070007, 0x00070007, + 0x00070007, 0x00070007, + + 0x16260806, 0x16260806, + 0x16260806, 0x16260806, + 0x16260806, 0x16260806, + 0x16260806, 0x16260806, + + // 10 - 1f + 0x22061806, 0x22061806, + 0x22061806, 0x22061806, + 0x22061806, 0x22061806, + 0x22061806, 0x22061806, + + 0x22061806, 0x22061806, + 0x22061806, 0x22061806, + 0x22061806, 0x22061806, + 0x22061806, 0x22061806, + + // 20 - 2f + 0x00070806, 0x00070806, + 0x00070806, 0x00070806, + 0x00070806, 0x00070806, + 0x00070806, 0x00070806, + + 0x00070806, 0x00070806, + 0x00070806, 0x00070806, + 0x00070806, 0x00070806, + 0x00070806, 0x00070806, +}; + +/* + * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in. + */ +static struct fb_fix_screeninfo ubicom32plio80_fix = { + .id = "Ubicom32", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .accel = FB_ACCEL_UBICOM32_PLIO80, +}; + +/* + * Filled in at probe time when we find out what the hardware supports + */ +static struct fb_var_screeninfo ubicom32plio80_var; + +/* + * Private data structure + */ +struct ubicom32plio80_drvdata { + struct fb_info *fbinfo; + bool cmap_alloc; + + /* + * The address of the framebuffer in memory + */ + void *fb; + void *fb_aligned; + + /* + * Total size of vram including alignment allowance + */ + u32 total_vram_size; + + /* + * Fake palette of 16 colors + */ + u32 pseudo_palette[PALETTE_ENTRIES_NO]; + + int irq_req; + + /* + * Current pointer and bytes left to transfer with the PLIO + */ + void *xfer_ptr; + u32 bytes_to_xfer; + u32 busy; +}; + +static struct platform_device *ubicom32plio80_platform_device; + +/* + * ubicom32plio80_isr + */ +static int ubicom32plio80_isr(int irq, void *appdata) +{ + struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)appdata; + + if (!ud->bytes_to_xfer) { + ubicom32_disable_interrupt(TX_FIFO_INT(PLIO_PORT)); + PLIO_NBR->intmask.txfifo_wm = 0; + ud->busy = 0; + return IRQ_HANDLED; + } + + asm volatile ( + ".rept 8 \n\t" + "move.4 (%[fifo]), (%[data])4++ \n\t" + ".endr \n\t" + : [data] "+a" (ud->xfer_ptr) + : [fifo] "a" (&PLIO_NBR->tx_lo) + ); + + ud->bytes_to_xfer -= 32; + + return IRQ_HANDLED; +} + +/* + * ubicom32plio80_update + */ +static void ubicom32plio80_update(struct ubicom32plio80_drvdata *ud, u32 *fb) +{ + struct ubicom32_io_port *ri = (struct ubicom32_io_port *)RI; + struct ubicom32_io_port *rd = (struct ubicom32_io_port *)RD; + + ud->xfer_ptr = fb; + ud->bytes_to_xfer = (xres * yres * 2) - 64; + ud->busy = 1; + + ri->gpio_mask = 0; + rd->gpio_mask &= ~((1 << 4) | (1 << 2)); + + *(u32 *)(&PLIO_NBR->intclr) = ~0; + PLIO_NBR->intmask.txfifo_wm = 1; + PLIO_NBR->fifo_wm.tx = 8; + ubicom32_enable_interrupt(TX_FIFO_INT(PLIO_PORT)); + + asm volatile ( + ".rept 16 \n\t" + "move.4 (%[fifo]), (%[data])4++ \n\t" + ".endr \n\t" + : [data] "+a" (ud->xfer_ptr) + : [fifo] "a" (&PLIO_NBR->tx_lo) + ); +} + +/* + * ubicom32plio80_pan_display + * Pans the display to a given location. Supports only y direction panning. + */ +static int ubicom32plio80_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) +{ + struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)fbi->par; + void *new_addr; + + /* + * Get the last y line that would be displayed. Since we don't support YWRAP, + * it must be less than our virtual y size. + */ + u32 lasty = var->yoffset + var->yres; + if (lasty > fbi->var.yres_virtual) { + /* + * We would fall off the end of our frame buffer if we panned here. + */ + return -EINVAL; + } + + if (var->xoffset) { + /* + * We don't support panning in the x direction + */ + return -EINVAL; + } + + /* + * Everything looks sane, go ahead and pan + * + * We have to calculate a new address for the VDC to look at + */ + new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length); + + return 0; +} + +/* + * ubicom32plio80_setcolreg + * Sets a color in our virtual palette + */ +static int ubicom32plio80_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi) +{ + u32 *palette = fbi->pseudo_palette; + + if (regno >= PALETTE_ENTRIES_NO) { + return -EINVAL; + } + + /* + * We only use 8 bits from each color + */ + red >>= 8; + green >>= 8; + blue >>= 8; + + /* + * Convert any grayscale values + */ + if (fbi->var.grayscale) { + u16 gray = red + green + blue; + gray += (gray >> 2) + (gray >> 3) - (gray >> 7); + gray >>= 2; + if (gray > 255) { + gray = 255; + } + red = gray; + blue = gray; + green = gray; + } + + palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) | + (blue << fbi->var.blue.offset); + + return 0; +} + +/* + * ubicom32plio80_mmap + */ +static int ubicom32plio80_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)info->par; + + vma->vm_start = (unsigned long)(ud->fb_aligned); + + vma->vm_end = vma->vm_start + info->fix.smem_len; + + /* For those who don't understand how mmap works, go read + * Documentation/nommu-mmap.txt. + * For those that do, you will know that the VM_MAYSHARE flag + * must be set in the vma->vm_flags structure on noMMU + * Other flags can be set, and are documented in + * include/linux/mm.h + */ + + vma->vm_flags |= VM_MAYSHARE | VM_SHARED; + + return 0; +} + +/* + * ubicom32plio80_check_var + * Check the var, tweak it but don't change operational parameters. + */ +static int ubicom32plio80_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)info->par; + u32 line_size = var->xres * (BITS_PER_PIXEL / 8); + + /* + * See if we can handle this bpp + */ + if (var->bits_per_pixel > BITS_PER_PIXEL) { + return -EINVAL; + } + var->bits_per_pixel = BITS_PER_PIXEL; + + /* + * See if we have enough memory to handle this resolution + */ + if ((line_size * var->yres * BITS_PER_PIXEL / 8) > ud->total_vram_size) { + return -EINVAL; + } + + var->xres_virtual = var->xres; + var->yres_virtual = ud->total_vram_size / line_size; + + var->red.length = 5; + var->green.length = 6; + var->green.offset = 5; + var->blue.length = 5; + var->transp.offset = var->transp.length = 0; + + if (bgr) { + var->red.offset = 0; + var->blue.offset = 11; + } else { + var->red.offset = 11; + var->blue.offset = 0; + } + + var->nonstd = 0; + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + var->sync = 0; + + return 0; +} + +/* + * ubicom32plio80_set_par + * Set the video mode according to info->var + */ +static int ubicom32plio80_set_par(struct fb_info *info) +{ + /* + * Anything changed? + */ + if ((xres == info->var.xres) && (yres == info->var.yres)) { + return 0; + } + + /* + * Implement changes + */ + xres = info->var.xres; + yres = info->var.yres; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.xpanstep = 0; + info->fix.ypanstep = 1; + info->fix.line_length = xres * (BITS_PER_PIXEL / 8); + + return 0; +} + +/* + * ubicom32plio80_ops + * List of supported operations + */ +static struct fb_ops ubicom32plio80_ops = +{ + .owner = THIS_MODULE, + .fb_pan_display = ubicom32plio80_pan_display, + .fb_setcolreg = ubicom32plio80_setcolreg, + .fb_mmap = ubicom32plio80_mmap, + .fb_check_var = ubicom32plio80_check_var, + .fb_set_par = ubicom32plio80_set_par, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +/* + * ubicom32plio80_release + */ +static int ubicom32plio80_release(struct device *dev) +{ + struct ubicom32plio80_drvdata *ud = dev_get_drvdata(dev); + + unregister_framebuffer(ud->fbinfo); + + if (ud->irq_req) { + free_irq(TX_FIFO_INT(PLIO_PORT), ud); + } + if (ud->cmap_alloc) { + fb_dealloc_cmap(&ud->fbinfo->cmap); + } + + if (ud->fb) { + kfree(ud->fb); + } + + framebuffer_release(ud->fbinfo); + dev_set_drvdata(dev, NULL); + + return 0; +} + +/* + * ubicom32plio80_platform_probe + */ +static int __init ubicom32plio80_platform_probe(struct platform_device *pdev) +{ + struct ubicom32plio80_drvdata *ud; + struct fb_info *fbinfo; + int rc; + size_t fbsize; + struct device *dev = &pdev->dev; + int offset; + + /* + * This is the minimum VRAM size + */ + fbsize = xres * yres * 2; + if (!vram_size) { + vram_size = (fbsize + 1023) / 1024; + } else { + if (fbsize > (vram_size * 1024)) { + dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize); + return -ENOMEM; // should be ebadparam? + } + } + + /* + * Allocate the framebuffer instance + our private data + */ + fbinfo = framebuffer_alloc(sizeof(struct ubicom32plio80_drvdata), &pdev->dev); + if (!fbinfo) { + dev_err(dev, "Not enough memory to allocate instance.\n"); + return -ENOMEM; + } + + /* + * Fill in our private data. + */ + ud = (struct ubicom32plio80_drvdata *)fbinfo->par; + ud->fbinfo = fbinfo; + dev_set_drvdata(dev, ud); + + /* + * Allocate and align the requested amount of VRAM + */ + ud->total_vram_size = (vram_size * 1024) + UBICOM32PLIO80_ALIGNMENT; + ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL); + if (ud->fb == NULL) { + dev_err(dev, "Couldn't allocate VRAM\n"); + rc = -ENOMEM; + goto fail; + } + + offset = (u32_t)ud->fb & (UBICOM32PLIO80_ALIGNMENT - 1); + if (!offset) { + ud->fb_aligned = ud->fb; + } else { + offset = UBICOM32PLIO80_ALIGNMENT - offset; + ud->fb_aligned = ud->fb + offset; + } + + /* + * Clear the entire frame buffer + */ + memset(ud->fb_aligned, 0, vram_size * 1024); + + /* + * Fill in the fb_var_screeninfo structure + */ + memset(&ubicom32plio80_var, 0, sizeof(ubicom32plio80_var)); + ubicom32plio80_var.bits_per_pixel = BITS_PER_PIXEL; + ubicom32plio80_var.red.length = 5; + ubicom32plio80_var.green.length = 6; + ubicom32plio80_var.green.offset = 5; + ubicom32plio80_var.blue.length = 5; + ubicom32plio80_var.activate = FB_ACTIVATE_NOW; + + if (bgr) { + ubicom32plio80_var.red.offset = 0; + ubicom32plio80_var.blue.offset = 11; + } else { + ubicom32plio80_var.red.offset = 11; + ubicom32plio80_var.blue.offset = 0; + } + + /* + * Fill in the fb_info structure + */ + ud->fbinfo->device = dev; + ud->fbinfo->screen_base = (void *)ud->fb_aligned; + ud->fbinfo->fbops = &ubicom32plio80_ops; + ud->fbinfo->fix = ubicom32plio80_fix; + ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned; + ud->fbinfo->fix.smem_len = vram_size * 1024; + ud->fbinfo->fix.line_length = xres * 2; + ud->fbinfo->fix.mmio_start = (u32)ud; + ud->fbinfo->fix.mmio_len = sizeof(struct ubicom32plio80_drvdata); + + /* + * We support panning in the y direction only + */ + ud->fbinfo->fix.xpanstep = 0; + ud->fbinfo->fix.ypanstep = 1; + + ud->fbinfo->pseudo_palette = ud->pseudo_palette; + ud->fbinfo->flags = FBINFO_DEFAULT; + ud->fbinfo->var = ubicom32plio80_var; + ud->fbinfo->var.xres = xres; + ud->fbinfo->var.yres = yres; + + /* + * We cannot pan in the X direction, so xres_virtual is xres + * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length + */ + ud->fbinfo->var.xres_virtual = xres; + ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length; + + /* + * Allocate a color map + */ + rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0); + if (rc) { + dev_err(dev, "Fail to allocate colormap (%d entries)\n", + PALETTE_ENTRIES_NO); + goto fail; + } + ud->cmap_alloc = true; + + /* + * Register new frame buffer + */ + rc = register_framebuffer(ud->fbinfo); + if (rc) { + dev_err(dev, "Could not register frame buffer\n"); + goto fail; + } + + /* + * request the PLIO IRQ + */ + rc = request_irq(TX_FIFO_INT(PLIO_PORT), ubicom32plio80_isr, IRQF_DISABLED, "ubicom32plio80", ud); + if (rc) { + dev_err(dev, "Could not request IRQ\n"); + goto fail; + } + ud->irq_req = 1; + + /* + * Clear any garbage out of the TX FIFOs (idif_txfifo_flush) + * + * cast through ubicom32_io_port to make sure the compiler does a word write + */ + ((struct ubicom32_io_port *)PLIO_NBR)->int_set = (1 << 18); + + /* + * Start up the state machine + */ + plio_init(&plio_fctl, &plio_config, (plio_sram_t *)ubicom32plio80_plio_fsm, sizeof(ubicom32plio80_plio_fsm)); + PLIO_NBR->fctl0.pfsm_cmd = 0; + + ubicom32plio80_update(ud, ud->fb_aligned); + + /* + * Tell the log we are here + */ + dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n", + ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres, + ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual); + + /* + * Success + */ + return 0; + +fail: + ubicom32plio80_release(dev); + return rc; +} + +/* + * ubicom32plio80_platform_remove + */ +static int ubicom32plio80_platform_remove(struct platform_device *pdev) +{ + dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n"); + return ubicom32plio80_release(&pdev->dev); +} + +static struct platform_driver ubicom32plio80_platform_driver = { + .probe = ubicom32plio80_platform_probe, + .remove = ubicom32plio80_platform_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +#ifndef MODULE +/* + * ubicom32plio80_setup + * Process kernel boot options + */ +static int __init ubicom32plio80_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) { + return 0; + } + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) { + continue; + } + + if (!strncmp(this_opt, "vram_size=", 10)) { + vram_size = simple_strtoul(this_opt + 10, NULL, 0); + continue; + } + + if (!strncmp(this_opt, "bgr=", 4)) { + bgr = simple_strtoul(this_opt + 4, NULL, 0); + continue; + } + + if (!strncmp(this_opt, "xres=", 5)) { + xres = simple_strtoul(this_opt + 5, NULL, 0); + continue; + } + + if (!strncmp(this_opt, "yres=", 5)) { + yres = simple_strtoul(this_opt + 5, NULL, 0); + continue; + } + } + return 0; +} +#endif /* MODULE */ + +/* + * ubicom32plio80_init + */ +static int __devinit ubicom32plio80_init(void) +{ + int ret; + +#ifndef MODULE + /* + * Get kernel boot options (in 'video=ubicom32plio80:') + */ + char *option = NULL; + + if (fb_get_options(DRIVER_NAME, &option)) { + return -ENODEV; + } + ubicom32plio80_setup(option); +#endif /* MODULE */ + + ret = platform_driver_register(&ubicom32plio80_platform_driver); + + if (!ret) { + ubicom32plio80_platform_device = platform_device_alloc(DRIVER_NAME, 0); + + if (ubicom32plio80_platform_device) + ret = platform_device_add(ubicom32plio80_platform_device); + else + ret = -ENOMEM; + + if (ret) { + platform_device_put(ubicom32plio80_platform_device); + platform_driver_unregister(&ubicom32plio80_platform_driver); + } + } + + return ret; +} +module_init(ubicom32plio80_init); + +/* + * ubicom32plio80_exit + */ +static void __exit ubicom32plio80_exit(void) +{ + platform_device_unregister(ubicom32plio80_platform_device); + platform_driver_unregister(&ubicom32plio80_platform_driver); +} +module_exit(ubicom32plio80_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); diff --git a/target/linux/ubicom32/files/drivers/video/ubicom32vfb.c b/target/linux/ubicom32/files/drivers/video/ubicom32vfb.c new file mode 100644 index 000000000..8478273d4 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/video/ubicom32vfb.c @@ -0,0 +1,603 @@ +/* + * drivers/video/ubicom32vfb.c + * Ubicom32 virtual frame buffer driver + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +/* + * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by + * Geert Uytterhoeven. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "ubicom32vfb" +#define DRIVER_DESCRIPTION "Ubicom32 virtual frame buffer driver" + +#define PALETTE_ENTRIES_NO 16 + +/* + * Option variables + * + * vram_size: VRAM size in kilobytes, subject to alignment + */ +static int vram_size = 0; +module_param(vram_size, int, 0); +MODULE_PARM_DESC(vram_size, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment"); + +static int xres = 320; +module_param(xres, int, 0); +MODULE_PARM_DESC(xres, "x (horizontal) resolution"); + +static int yres = 240; +module_param(yres, int, 0); +MODULE_PARM_DESC(yres, "y (vertical) resolution"); + +static int bgr = 0; +module_param(bgr, int, 0); +MODULE_PARM_DESC(bgr, "display is BGR (Blue is MSB)"); + +#define BITS_PER_PIXEL 16 + +/* + * Buffer alignment, must not be 0 + */ +#define UBICOM32VFB_ALIGNMENT 4 + +/* + * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in. + */ +static struct fb_fix_screeninfo ubicom32vfb_fix = { + .id = "Ubicom32", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .accel = FB_ACCEL_UBICOM32_VFB, +}; + +/* + * Filled in at probe time when we find out what the hardware supports + */ +static struct fb_var_screeninfo ubicom32vfb_var; + +/* + * Private data structure + */ +struct ubicom32vfb_drvdata { + struct fb_info *fbinfo; + bool cmap_alloc; + + /* + * The address of the framebuffer in memory + */ + void *fb; + void *fb_aligned; + + /* + * Total size of vram including alignment allowance + */ + u32 total_vram_size; + + /* + * Fake palette of 16 colors + */ + u32 pseudo_palette[PALETTE_ENTRIES_NO]; +}; + +static struct platform_device *ubicom32vfb_platform_device; + +/* + * ubicom32vfb_pan_display + * Pans the display to a given location. Supports only y direction panning. + */ +static int ubicom32vfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) +{ + struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)fbi->par; + void *new_addr; + + /* + * Get the last y line that would be displayed. Since we don't support YWRAP, + * it must be less than our virtual y size. + */ + u32 lasty = var->yoffset + var->yres; + if (lasty > fbi->var.yres_virtual) { + /* + * We would fall off the end of our frame buffer if we panned here. + */ + return -EINVAL; + } + + if (var->xoffset) { + /* + * We don't support panning in the x direction + */ + return -EINVAL; + } + + /* + * Everything looks sane, go ahead and pan + * + * We have to calculate a new address for the VDC to look at + */ + new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length); + + return 0; +} + +/* + * ubicom32vfb_setcolreg + * Sets a color in our virtual palette + */ +static int ubicom32vfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi) +{ + u32 *palette = fbi->pseudo_palette; + + if (regno >= PALETTE_ENTRIES_NO) { + return -EINVAL; + } + + /* + * We only use 8 bits from each color + */ + red >>= 8; + green >>= 8; + blue >>= 8; + + /* + * Convert any grayscale values + */ + if (fbi->var.grayscale) { + u16 gray = red + green + blue; + gray += (gray >> 2) + (gray >> 3) - (gray >> 7); + gray >>= 2; + if (gray > 255) { + gray = 255; + } + red = gray; + blue = gray; + green = gray; + } + + palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) | + (blue << fbi->var.blue.offset); + + return 0; +} + +/* + * ubicom32vfb_mmap + */ +static int ubicom32vfb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)info->par; + + vma->vm_start = (unsigned long)(ud->fb_aligned); + + vma->vm_end = vma->vm_start + info->fix.smem_len; + + /* For those who don't understand how mmap works, go read + * Documentation/nommu-mmap.txt. + * For those that do, you will know that the VM_MAYSHARE flag + * must be set in the vma->vm_flags structure on noMMU + * Other flags can be set, and are documented in + * include/linux/mm.h + */ + + vma->vm_flags |= VM_MAYSHARE | VM_SHARED; + + return 0; +} + +/* + * ubicom32vfb_check_var + * Check the var, tweak it but don't change operational parameters. + */ +static int ubicom32vfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)info->par; + u32 line_size = var->xres * (BITS_PER_PIXEL / 8); + + /* + * See if we can handle this bpp + */ + if (var->bits_per_pixel > BITS_PER_PIXEL) { + return -EINVAL; + } + var->bits_per_pixel = BITS_PER_PIXEL; + + /* + * See if we have enough memory to handle this resolution + */ + if ((line_size * var->yres * BITS_PER_PIXEL / 8) > ud->total_vram_size) { + return -EINVAL; + } + + var->xres_virtual = var->xres; + var->yres_virtual = ud->total_vram_size / line_size; + + var->red.length = 5; + var->green.length = 6; + var->green.offset = 5; + var->blue.length = 5; + var->transp.offset = var->transp.length = 0; + + if (bgr) { + var->red.offset = 0; + var->blue.offset = 11; + } else { + var->red.offset = 11; + var->blue.offset = 0; + } + + var->nonstd = 0; + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + var->sync = 0; + + return 0; +} + +/* + * ubicom32vfb_set_par + * Set the video mode according to info->var + */ +static int ubicom32vfb_set_par(struct fb_info *info) +{ + /* + * Anything changed? + */ + if ((xres == info->var.xres) && (yres == info->var.yres)) { + return 0; + } + + /* + * Implement changes + */ + xres = info->var.xres; + yres = info->var.yres; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.xpanstep = 0; + info->fix.ypanstep = 1; + info->fix.line_length = xres * (BITS_PER_PIXEL / 8); + + return 0; +} + +/* + * ubicom32vfb_ops + * List of supported operations + */ +static struct fb_ops ubicom32vfb_ops = +{ + .owner = THIS_MODULE, + .fb_pan_display = ubicom32vfb_pan_display, + .fb_setcolreg = ubicom32vfb_setcolreg, + .fb_mmap = ubicom32vfb_mmap, + .fb_check_var = ubicom32vfb_check_var, + .fb_set_par = ubicom32vfb_set_par, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +/* + * ubicom32vfb_release + */ +static int ubicom32vfb_release(struct device *dev) +{ + struct ubicom32vfb_drvdata *ud = dev_get_drvdata(dev); + + unregister_framebuffer(ud->fbinfo); + + if (ud->cmap_alloc) { + fb_dealloc_cmap(&ud->fbinfo->cmap); + } + + if (ud->fb) { + kfree(ud->fb); + } + + framebuffer_release(ud->fbinfo); + dev_set_drvdata(dev, NULL); + + return 0; +} + +/* + * ubicom32vfb_platform_probe + */ +static int __init ubicom32vfb_platform_probe(struct platform_device *pdev) +{ + struct ubicom32vfb_drvdata *ud; + struct fb_info *fbinfo; + int rc; + size_t fbsize; + struct device *dev = &pdev->dev; + int offset; + + /* + * This is the minimum VRAM size + */ + fbsize = xres * yres * 2; + if (!vram_size) { + vram_size = (fbsize + 1023) / 1024; + } else { + if (fbsize > (vram_size * 1024)) { + dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize); + return -ENOMEM; // should be ebadparam? + } + } + + /* + * Allocate the framebuffer instance + our private data + */ + fbinfo = framebuffer_alloc(sizeof(struct ubicom32vfb_drvdata), &pdev->dev); + if (!fbinfo) { + dev_err(dev, "Not enough memory to allocate instance.\n"); + return -ENOMEM; + } + + /* + * Fill in our private data. + */ + ud = (struct ubicom32vfb_drvdata *)fbinfo->par; + ud->fbinfo = fbinfo; + dev_set_drvdata(dev, ud); + + /* + * Allocate and align the requested amount of VRAM + */ + ud->total_vram_size = (vram_size * 1024) + UBICOM32VFB_ALIGNMENT; + ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL); + if (ud->fb == NULL) { + dev_err(dev, "Couldn't allocate VRAM\n"); + rc = -ENOMEM; + goto fail; + } + + offset = (u32_t)ud->fb & (UBICOM32VFB_ALIGNMENT - 1); + if (!offset) { + ud->fb_aligned = ud->fb; + } else { + offset = UBICOM32VFB_ALIGNMENT - offset; + ud->fb_aligned = ud->fb + offset; + } + + /* + * Clear the entire frame buffer + */ + memset(ud->fb_aligned, 0, vram_size * 1024); + + /* + * Fill in the fb_var_screeninfo structure + */ + memset(&ubicom32vfb_var, 0, sizeof(ubicom32vfb_var)); + ubicom32vfb_var.bits_per_pixel = BITS_PER_PIXEL; + ubicom32vfb_var.red.length = 5; + ubicom32vfb_var.green.length = 6; + ubicom32vfb_var.green.offset = 5; + ubicom32vfb_var.blue.length = 5; + ubicom32vfb_var.activate = FB_ACTIVATE_NOW; + + if (bgr) { + ubicom32vfb_var.red.offset = 0; + ubicom32vfb_var.blue.offset = 11; + } else { + ubicom32vfb_var.red.offset = 11; + ubicom32vfb_var.blue.offset = 0; + } + + /* + * Fill in the fb_info structure + */ + ud->fbinfo->device = dev; + ud->fbinfo->screen_base = (void *)ud->fb_aligned; + ud->fbinfo->fbops = &ubicom32vfb_ops; + ud->fbinfo->fix = ubicom32vfb_fix; + ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned; + ud->fbinfo->fix.smem_len = vram_size * 1024; + ud->fbinfo->fix.line_length = xres * 2; + ud->fbinfo->fix.mmio_start = (u32)ud; + ud->fbinfo->fix.mmio_len = sizeof(struct ubicom32vfb_drvdata); + + /* + * We support panning in the y direction only + */ + ud->fbinfo->fix.xpanstep = 0; + ud->fbinfo->fix.ypanstep = 1; + + ud->fbinfo->pseudo_palette = ud->pseudo_palette; + ud->fbinfo->flags = FBINFO_DEFAULT; + ud->fbinfo->var = ubicom32vfb_var; + ud->fbinfo->var.xres = xres; + ud->fbinfo->var.yres = yres; + + /* + * We cannot pan in the X direction, so xres_virtual is xres + * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length + */ + ud->fbinfo->var.xres_virtual = xres; + ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length; + + /* + * Allocate a color map + */ + rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0); + if (rc) { + dev_err(dev, "Fail to allocate colormap (%d entries)\n", + PALETTE_ENTRIES_NO); + goto fail; + } + ud->cmap_alloc = true; + + /* + * Register new frame buffer + */ + rc = register_framebuffer(ud->fbinfo); + if (rc) { + dev_err(dev, "Could not register frame buffer\n"); + goto fail; + } + + /* + * Tell the log we are here + */ + dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n", + ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres, + ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual); + + /* + * Success + */ + return 0; + +fail: + ubicom32vfb_release(dev); + return rc; +} + +/* + * ubicom32vfb_platform_remove + */ +static int ubicom32vfb_platform_remove(struct platform_device *pdev) +{ + dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n"); + return ubicom32vfb_release(&pdev->dev); +} + +static struct platform_driver ubicom32vfb_platform_driver = { + .probe = ubicom32vfb_platform_probe, + .remove = ubicom32vfb_platform_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +#ifndef MODULE +/* + * ubicom32vfb_setup + * Process kernel boot options + */ +static int __init ubicom32vfb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) { + return 0; + } + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) { + continue; + } + + if (!strncmp(this_opt, "vram_size=", 10)) { + vram_size = simple_strtoul(this_opt + 10, NULL, 0); + continue; + } + + if (!strncmp(this_opt, "bgr=", 4)) { + bgr = simple_strtoul(this_opt + 4, NULL, 0); + continue; + } + + if (!strncmp(this_opt, "xres=", 5)) { + xres = simple_strtoul(this_opt + 5, NULL, 0); + continue; + } + + if (!strncmp(this_opt, "yres=", 5)) { + yres = simple_strtoul(this_opt + 5, NULL, 0); + continue; + } + } + return 0; +} +#endif /* MODULE */ + +/* + * ubicom32vfb_init + */ +static int __devinit ubicom32vfb_init(void) +{ + int ret; + +#ifndef MODULE + /* + * Get kernel boot options (in 'video=ubicom32vfb:') + */ + char *option = NULL; + + if (fb_get_options(DRIVER_NAME, &option)) { + return -ENODEV; + } + ubicom32vfb_setup(option); +#endif /* MODULE */ + + ret = platform_driver_register(&ubicom32vfb_platform_driver); + +#ifdef CONFIG_FB_UBICOM32_VIRTUAL_NOAUTO + return ret; +#else + if (!ret) { + ubicom32vfb_platform_device = platform_device_alloc(DRIVER_NAME, 0); + + if (ubicom32vfb_platform_device) + ret = platform_device_add(ubicom32vfb_platform_device); + else + ret = -ENOMEM; + + if (ret) { + platform_device_put(ubicom32vfb_platform_device); + platform_driver_unregister(&ubicom32vfb_platform_driver); + } + } + + return ret; +#endif +} +module_init(ubicom32vfb_init); + +/* + * ubicom32vfb_exit + */ +static void __exit ubicom32vfb_exit(void) +{ + platform_device_unregister(ubicom32vfb_platform_device); + platform_driver_unregister(&ubicom32vfb_platform_driver); +} +module_exit(ubicom32vfb_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); diff --git a/target/linux/ubicom32/files/drivers/watchdog/ubi32_wdt.c b/target/linux/ubicom32/files/drivers/watchdog/ubi32_wdt.c new file mode 100644 index 000000000..2c5b92187 --- /dev/null +++ b/target/linux/ubicom32/files/drivers/watchdog/ubi32_wdt.c @@ -0,0 +1,630 @@ +/* + * drivers/watchdog/ubi32_wdt.c + * Ubicom32 Watchdog Driver + * + * Originally based on softdog.c + * Copyright 2006-2007 Analog Devices Inc. + * Copyright 2006-2007 Michele d'Amico + * Copyright 1996 Alan Cox + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WATCHDOG_NAME "ubi32-wdt" +#define PFX WATCHDOG_NAME ": " + +#define OSC1_FREQ 12000000 +#define WATCHDOG_SEC_TO_CYC(x) (OSC1_FREQ * (x)) +#define WATCHDOG_MAX_SEC (0xffffffff / OSC1_FREQ) + +#define MIN_PROCESSOR_ADDRESS 0x03000000 + +static DEFINE_SPINLOCK(ubi32_wdt_spinlock); + +#define WATCHDOG_TIMEOUT 20 + +#if defined(CONFIG_WATCHDOG_NOWAYOUT) +#define WATCHDOG_NOWAYOUT 1 +#else +#define WATCHDOG_NOWAYOUT 0 +#endif + +static unsigned int timeout = WATCHDOG_TIMEOUT; +static int nowayout = WATCHDOG_NOWAYOUT; +static struct watchdog_info ubi32_wdt_info; +static unsigned long open_check; +static char expect_close; + +#if !defined(CONFIG_SMP) +#define UBI32_WDT_LOCK(lock, flags) local_irq_save(flags) +#define UBI32_WDT_UNLOCK(lock, flags) local_irq_restore(flags) +#define UBI32_WDT_LOCK_CHECK() +#else +#define UBI32_WDT_LOCK(lock, flags) spin_lock_irqsave((lock), (flags)); +#define UBI32_WDT_UNLOCK(lock, flags) spin_unlock_irqrestore((lock), (flags)); +#define UBI32_WDT_LOCK_CHECK() BUG_ON(!spin_is_locked(&ubi32_wdt_spinlock)); +#endif + +/* + * ubi32_wdt_remaining() + * Return the approximate number of seconds remaining + */ +static int ubi32_wdt_remaining(void) +{ + int compare; + int curr; + + UBI32_WDT_LOCK_CHECK(); + + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); + compare = ubicom32_read_reg(&UBICOM32_IO_TIMER->wdcom); + curr = ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval); + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); + return (compare - curr) / OSC1_FREQ; + +} + +/* + * ubi32_wdt_keepalive() + * Keep the Userspace Watchdog Alive + * + * The Userspace watchdog got a KeepAlive: schedule the next timeout. + */ +static int ubi32_wdt_keepalive(void) +{ + UBI32_WDT_LOCK_CHECK(); + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); + ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcom, + ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval) + + WATCHDOG_SEC_TO_CYC(timeout)); + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); + return 0; +} + +/* + * ubi32_wdt_stop() + * Stop the on-chip Watchdog + */ +static int ubi32_wdt_stop(void) +{ + UBI32_WDT_LOCK_CHECK(); + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); + ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcfg, TIMER_WATCHDOG_DISABLE); + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); + return 0; +} + +/* + * ubi32_wdt_start() + * Start the on-chip Watchdog + */ +static int ubi32_wdt_start(void) +{ + UBI32_WDT_LOCK_CHECK(); + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); + ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcom, + ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval) + + WATCHDOG_SEC_TO_CYC(timeout)); + ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcfg, ~TIMER_WATCHDOG_DISABLE); + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); + return 0; +} + +/* + * ubi32_wdt_running() + * Return true if the watchdog is configured + */ +static int ubi32_wdt_running(void) +{ + int enabled; + + UBI32_WDT_LOCK_CHECK(); + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); + enabled = ubicom32_read_reg(&UBICOM32_IO_TIMER->wdcfg) == ~TIMER_WATCHDOG_DISABLE; + ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); + return enabled; +} + +/* + * ubi32_wdt_set_timeout() + * Set the Userspace Watchdog timeout + * + * - @t: new timeout value (in seconds) + */ +static int ubi32_wdt_set_timeout(unsigned long t) +{ + UBI32_WDT_LOCK_CHECK(); + + if (t > WATCHDOG_MAX_SEC) { + printk(KERN_WARNING PFX "request to large: %ld [1-%d] sec)\n", t, WATCHDOG_MAX_SEC); + return -EINVAL; + } + + /* + * If we are running, then reset the time value so + * that the new value has an immediate effect. + */ + timeout = t; + if (ubi32_wdt_running()) { + ubi32_wdt_keepalive(); + } + return 0; +} + +/* + * ubi32_wdt_open() + * Open the Device + */ +static int ubi32_wdt_open(struct inode *inode, struct file *file) +{ + unsigned long flags; + + if (test_and_set_bit(0, &open_check)) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + ubi32_wdt_start(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + + return nonseekable_open(inode, file); +} + +/* + * ubi32_wdt_close() + * Close the Device + */ +static int ubi32_wdt_release(struct inode *inode, struct file *file) +{ + unsigned long flags; + + /* + * If we don't expect a close, then the watchdog continues + * even though the device is closed. The caller will have + * a full timeout value to reopen the device and continue + * stroking it. + */ + if (expect_close != 42) { + printk(KERN_CRIT PFX + "Unexpected close, not stopping watchdog!\n"); + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + ubi32_wdt_keepalive(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + } else { + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + ubi32_wdt_stop(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + } + + expect_close = 0; + clear_bit(0, &open_check); + return 0; +} + +/* + * ubi32_wdt_write() + * Write to Device + * + * If the user writes nothing, nothing happens. + * If the user writes a V, then we expect a close and allow a release. + * If the user writes anything else, it is ignored. + */ +static ssize_t ubi32_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + size_t i; + unsigned long flags; + + /* + * Every write resets the expect_close. The last write + * must be a V to allow shutdown on close. + */ + expect_close = 0; + + /* + * Empty writes still ping. + */ + if (!len) { + goto ping; + } + + /* + * If nowayout is set, it does not matter if the caller + * is trying to send the magic 'V' we will not allow a + * close to stop us. + */ + if (nowayout) { + goto ping; + } + + /* + * See if the program wrote a 'V' and if so disable + * the watchdog on release. + */ + for (i = 0; i < len; i++) { + char c; + if (get_user(c, data + i)) { + return -EFAULT; + } + + if (c == 'V') { + expect_close = 42; + } + } + +ping: + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + ubi32_wdt_keepalive(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + return len; +} + +/* + * ubi32_wdt_ioctl() + * Query the watchdog device. + * + * Query basic information from the device or ping it, as outlined by the + * watchdog API. + */ +static long ubi32_wdt_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &ubi32_wdt_info, sizeof(ubi32_wdt_info))) { + return -EFAULT; + } + return 0; + + case WDIOC_GETSTATUS: { + unsigned long flags; + int running; + + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + running = ubi32_wdt_running(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + return running; + } + + case WDIOC_GETBOOTSTATUS: + return ubicom32_get_reset_reason(); + + case WDIOC_SETOPTIONS: { + unsigned long flags; + int options, ret = -EINVAL; + + /* + * The sample application does not pass a pointer + * but directly passes a value of 1 or 2; however + * all of the implementations (and thus probably + * the real applications) pass a pointer to a value. + * + * It should be noted that WDIOC_SETOPTIONS is defined as + * _IOR(WATCHDOG_IOCTL_BASE, 4, int), which means + * that it should be an int and NOT a pointer. + * + * TODO: Examine this code for future chips. + * TODO: Report the sample code defect. + */ + if ((int)p < MIN_PROCESSOR_ADDRESS) { + options = (int)p; + } else { + if (get_user(options, p)) + return -EFAULT; + } + + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + if (options & WDIOS_DISABLECARD) { + ubi32_wdt_stop(); + ret = 0; + } + if (options & WDIOS_ENABLECARD) { + ubi32_wdt_start(); + ret = 0; + } + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + return ret; + } + + case WDIOC_KEEPALIVE: { + unsigned long flags; + + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + ubi32_wdt_keepalive(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + return 0; + } + + case WDIOC_SETTIMEOUT: { + int new_timeout; + unsigned long flags; + int ret = 0; + + if (get_user(new_timeout, p)) + return -EFAULT; + + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + ret = ubi32_wdt_set_timeout(new_timeout); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + return ret; + + } + + case WDIOC_GETTIMEOUT: + return put_user(timeout, p); + + case WDIOC_GETTIMELEFT: { + unsigned long flags; + int remaining = 0; + + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + remaining = ubi32_wdt_remaining(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + return put_user(remaining, p); + } + + default: + return -ENOTTY; + } +} + +/* + * ubi32_wdt_notify_sys() + * Notification callback function for system events. + * + * Turn off the watchdog during a SYS_DOWN or SYS_HALT. + */ +static int ubi32_wdt_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + unsigned long flags; + + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + ubi32_wdt_stop(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + } + + return NOTIFY_DONE; +} + +#ifdef CONFIG_PM +static int state_before_suspend; + +/* + * ubi32_wdt_suspend() + * suspend the watchdog + * + * Remember if the watchdog was running and stop it. + */ +static int ubi32_wdt_suspend(struct platform_device *pdev, pm_message_t state) +{ + unsigned long flags; + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + state_before_suspend = ubi32_wdt_running(); + ubi32_wdt_stop(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + + return 0; +} + +/* + * ubi32_wdt_resume() + * Resume the watchdog + * + * If the watchdog was running, turn it back on. + */ +static int ubi32_wdt_resume(struct platform_device *pdev) +{ + if (state_before_suspend) { + unsigned long flags; + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + ubi32_wdt_set_timeout(timeout); + ubi32_wdt_start(); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + } + + return 0; +} +#else +# define ubi32_wdt_suspend NULL +# define ubi32_wdt_resume NULL +#endif + +static const struct file_operations ubi32_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = ubi32_wdt_write, + .unlocked_ioctl = ubi32_wdt_ioctl, + .open = ubi32_wdt_open, + .release = ubi32_wdt_release, +}; + +static struct miscdevice ubi32_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &ubi32_wdt_fops, +}; + +static struct watchdog_info ubi32_wdt_info = { + .identity = "Ubicom32 Watchdog", + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +static struct notifier_block ubi32_wdt_notifier = { + .notifier_call = ubi32_wdt_notify_sys, +}; + +/* + * ubi32_wdt_probe() + * Probe/register the watchdog module + * + * Registers the misc device and notifier handler. Actual device + * initialization is handled by ubi32_wdt_open(). + */ +static int __devinit ubi32_wdt_probe(struct platform_device *pdev) +{ + int ret; + + ret = register_reboot_notifier(&ubi32_wdt_notifier); + if (ret) { + printk(KERN_ERR PFX + "cannot register reboot notifier (err=%d)\n", ret); + return ret; + } + + ret = misc_register(&ubi32_wdt_miscdev); + if (ret) { + printk(KERN_ERR PFX + "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + unregister_reboot_notifier(&ubi32_wdt_notifier); + return ret; + } + + printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n", + timeout, nowayout); + + return 0; +} + +/* + * ubi32_wdt_remove() + * Uninstall the module + * + * Unregisters the misc device and notifier handler. Actual device + * deinitialization is handled by ubi32_wdt_close(). + */ +static int __devexit ubi32_wdt_remove(struct platform_device *pdev) +{ + misc_deregister(&ubi32_wdt_miscdev); + unregister_reboot_notifier(&ubi32_wdt_notifier); + return 0; +} + +static struct platform_device *ubi32_wdt_device; + +static struct platform_driver ubi32_wdt_driver = { + .probe = ubi32_wdt_probe, + .remove = __devexit_p(ubi32_wdt_remove), + .suspend = ubi32_wdt_suspend, + .resume = ubi32_wdt_resume, + .driver = { + .name = WATCHDOG_NAME, + .owner = THIS_MODULE, + }, +}; + +/* + * ubi32_wdt_init() + * Initialize the watchdog. + * + * Checks the module params and registers the platform device & driver. + * Real work is in the platform probe function. + */ +static int __init ubi32_wdt_init(void) +{ + unsigned long flags; + int ret; + + /* + * Check that the timeout value is within range + */ + spin_lock_irqsave(&ubi32_wdt_spinlock, flags); + ret = ubi32_wdt_set_timeout(timeout); + spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); + if (ret) { + return ret; + } + + /* + * Since this is an on-chip device and needs no board-specific + * resources, we'll handle all the platform device stuff here. + */ + ret = platform_driver_register(&ubi32_wdt_driver); + if (ret) { + printk(KERN_ERR PFX "unable to register driver\n"); + return ret; + } + + ubi32_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0); + if (IS_ERR(ubi32_wdt_device)) { + printk(KERN_ERR PFX "unable to register device\n"); + platform_driver_unregister(&ubi32_wdt_driver); + return PTR_ERR(ubi32_wdt_device); + } + + return 0; +} + +/* + * ubi32_wdt_exit() + * Deinitialize module + * + * Back out the platform device & driver steps. Real work is in the + * platform remove function. + */ +static void __exit ubi32_wdt_exit(void) +{ + platform_device_unregister(ubi32_wdt_device); + platform_driver_unregister(&ubi32_wdt_driver); +} + +module_init(ubi32_wdt_init); +module_exit(ubi32_wdt_exit); + +MODULE_AUTHOR("Sol Kavy"); +MODULE_DESCRIPTION("Ubicom32 Watchdog Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, + "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" + __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); diff --git a/target/linux/ubicom32/files/sound/ubicom32/Kconfig b/target/linux/ubicom32/files/sound/ubicom32/Kconfig new file mode 100644 index 000000000..c57bd34d9 --- /dev/null +++ b/target/linux/ubicom32/files/sound/ubicom32/Kconfig @@ -0,0 +1,42 @@ +# ALSA Ubicom32 drivers + +menuconfig SND_UBI32 + tristate "Ubicom32 sound devices" + select SND_PCM + default n + help + Say Y here to include support for audio on the Ubicom32 platform. + To compile this driver as a module, say M here: the module will be + called snd_ubi32. + +if SND_UBI32 + +config SND_UBI32_AUDIO_GENERIC_CAPTURE + bool "Generic Capture Support" + default n + help + Use this option to support ADCs which don't require special drivers. + +config SND_UBI32_AUDIO_GENERIC + bool "Generic Playback Support" + default n + help + Use this option to support DACs which don't require special drivers. + +comment "I2C Based Codecs" + +config SND_UBI32_AUDIO_CS4350 + bool "Cirrus Logic CS4350 DAC" + depends on I2C + default n + help + Support for the Cirrus Logic CS4350 DAC. + +config SND_UBI32_AUDIO_CS4384 + bool "Cirrus Logic CS4384 DAC" + depends on I2C + default n + help + Support for the Cirrus Logic CS4384 DAC. + +endif #SND_UBI32 diff --git a/target/linux/ubicom32/files/sound/ubicom32/Makefile b/target/linux/ubicom32/files/sound/ubicom32/Makefile new file mode 100644 index 000000000..ffdcc298a --- /dev/null +++ b/target/linux/ubicom32/files/sound/ubicom32/Makefile @@ -0,0 +1,41 @@ +# +# sound/ubicom32/Makefile +# Makefile for ALSA +# +# (C) Copyright 2009, Ubicom, Inc. +# +# This file is part of the Ubicom32 Linux Kernel Port. +# +# The Ubicom32 Linux Kernel Port is free software: you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 2 of the +# License, or (at your option) any later version. +# +# The Ubicom32 Linux Kernel Port is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Ubicom32 Linux Kernel Port. If not, +# see . +# +# Ubicom32 implementation derived from (with many thanks): +# arch/m68knommu +# arch/blackfin +# arch/parisc +# + +CFLAGS_ubi32.o += -O2 +snd-ubi32-pcm-objs := ubi32-pcm.o +snd-ubi32-generic-objs := ubi32-generic.o +snd-ubi32-generic-capture-objs := ubi32-generic-capture.o +snd-ubi32-cs4350-objs := ubi32-cs4350.o +snd-ubi32-cs4384-objs := ubi32-cs4384.o + +# Toplevel Module Dependency +obj-$(CONFIG_SND_UBI32) += snd-ubi32-pcm.o +obj-$(CONFIG_SND_UBI32_AUDIO_GENERIC) += snd-ubi32-generic.o +obj-$(CONFIG_SND_UBI32_AUDIO_GENERIC_CAPTURE) += snd-ubi32-generic-capture.o +obj-$(CONFIG_SND_UBI32_AUDIO_CS4350) += snd-ubi32-cs4350.o +obj-$(CONFIG_SND_UBI32_AUDIO_CS4384) += snd-ubi32-cs4384.o diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c new file mode 100644 index 000000000..7e6f9acbb --- /dev/null +++ b/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c @@ -0,0 +1,583 @@ +/* + * sound/ubicom32/ubi32-cs4350.c + * Interface to ubicom32 virtual audio peripheral - using CS4350 DAC + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ubi32.h" + +#define DRIVER_NAME "snd-ubi32-cs4350" + +/* + * Module properties + */ +static const struct i2c_device_id snd_ubi32_cs4350_id[] = { + {"cs4350", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ubicom32audio_id); + +static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ + +/* + * The dB scale for the Cirrus Logic cs4350. The output range is from + * -127.5 dB to 0 dB. + */ +static const DECLARE_TLV_DB_SCALE(snd_ubi32_cs4350_db, -12750, 50, 0); + +#define ubi32_cs4350_mute_info snd_ctl_boolean_stereo_info + +/* + * Private data for cs4350 chip + */ +struct ubi32_cs4350_priv { + /* + * The current volume settings + */ + uint8_t volume[2]; + + /* + * Bitmask of mutes MSB (unused, ..., unused, right_ch, left_ch) LSB + */ + uint8_t mute; + + /* + * Lock to protect this struct because callbacks are not atomic. + */ + spinlock_t lock; +}; + +/* + * The info for the cs4350. The volume currently has one channel, + * and 255 possible settings. + */ +static int ubi32_cs4350_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 255; // 8 bits in cirrus logic cs4350 volume register + return 0; +} + +static int ubi32_cs4350_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); + struct ubi32_cs4350_priv *cs4350_priv; + unsigned long flags; + + cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); + + spin_lock_irqsave(&cs4350_priv->lock, flags); + + ucontrol->value.integer.value[0] = cs4350_priv->volume[0]; + ucontrol->value.integer.value[1] = cs4350_priv->volume[1]; + + spin_unlock_irqrestore(&cs4350_priv->lock, flags); + + return 0; +} + +static int ubi32_cs4350_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); + struct i2c_client *client = (struct i2c_client *)ubi32_priv->client; + struct ubi32_cs4350_priv *cs4350_priv; + unsigned long flags; + int ret, changed; + char send[2]; + uint8_t volume_reg_value_left, volume_reg_value_right; + + changed = 0; + + cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); + volume_reg_value_left = 255 - (ucontrol->value.integer.value[0] & 0xFF); + volume_reg_value_right = 255 - (ucontrol->value.integer.value[1] & 0xFF); + +#if SND_UBI32_DEBUG + snd_printk(KERN_INFO "Setting volume: writing %d,%d to CS4350 volume registers\n", volume_reg_value_left, volume_reg_value_right); +#endif + spin_lock_irqsave(&cs4350_priv->lock, flags); + + if (cs4350_priv->volume[0] != ucontrol->value.integer.value[0]) { + send[0] = 0x05; // left channel + send[1] = volume_reg_value_left; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n"); + return changed; + } + cs4350_priv->volume[0] = ucontrol->value.integer.value[0]; + changed = 1; + } + + if (cs4350_priv->volume[1] != ucontrol->value.integer.value[1]) { + send[0] = 0x06; // right channel + send[1] = volume_reg_value_right; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set channel B volume on CS4350\n"); + return changed; + } + cs4350_priv->volume[1] = ucontrol->value.integer.value[1]; + changed = 1; + } + + spin_unlock_irqrestore(&cs4350_priv->lock, flags); + + return changed; +} + +static struct snd_kcontrol_new ubi32_cs4350_volume __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "PCM Playback Volume", + .info = ubi32_cs4350_volume_info, + .get = ubi32_cs4350_volume_get, + .put = ubi32_cs4350_volume_put, + .tlv.p = snd_ubi32_cs4350_db, +}; + +static int ubi32_cs4350_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); + struct ubi32_cs4350_priv *cs4350_priv; + unsigned long flags; + + cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); + + spin_lock_irqsave(&cs4350_priv->lock, flags); + + ucontrol->value.integer.value[0] = cs4350_priv->mute & 1; + ucontrol->value.integer.value[1] = (cs4350_priv->mute & (1 << 1)) ? 1 : 0; + + spin_unlock_irqrestore(&cs4350_priv->lock, flags); + + return 0; +} + +static int ubi32_cs4350_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); + struct i2c_client *client = (struct i2c_client *)ubi32_priv->client; + struct ubi32_cs4350_priv *cs4350_priv; + unsigned long flags; + int ret, changed; + char send[2]; + char recv[1]; + uint8_t mute; + + changed = 0; + + cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); + + spin_lock_irqsave(&cs4350_priv->lock, flags); + + if ((cs4350_priv->mute & 1) != ucontrol->value.integer.value[0]) { + send[0] = 0x04; + ret = i2c_master_send(client, send, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed to write to mute register: channel 0\n"); + return changed; + } + + ret = i2c_master_recv(client, recv, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed to read mute register: channel 0\n"); + return changed; + } + + mute = recv[0]; + + if (ucontrol->value.integer.value[0]) { + cs4350_priv->mute |= 1; + mute &= ~(1 << 4); +#if SND_UBI32_DEBUG + snd_printk(KERN_INFO "Unmuted channel A\n"); +#endif + } else { + cs4350_priv->mute &= ~1; + mute |= (1 << 4); +#if SND_UBI32_DEBUG + snd_printk(KERN_INFO "Muted channel A\n"); +#endif + } + + send[0] = 0x04; + send[1] = mute; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n"); + return changed; + } + changed = 1; + } + + if (((cs4350_priv->mute & 2) >> 1) != ucontrol->value.integer.value[1]) { + send[0] = 0x04; + ret = i2c_master_send(client, send, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed to write to mute register: channel 1\n"); + return changed; + } + + ret = i2c_master_recv(client, recv, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed to read mute register: channel 1\n"); + return changed; + } + + mute = recv[0]; + + if (ucontrol->value.integer.value[1]) { + cs4350_priv->mute |= (1 << 1); + mute &= ~(1 << 3); +#if SND_UBI32_DEBUG + snd_printk(KERN_INFO "Unmuted channel B\n"); +#endif + } else { + cs4350_priv->mute &= ~(1 << 1); + mute |= (1 << 3); +#if SND_UBI32_DEBUG + snd_printk(KERN_INFO "Muted channel B\n"); +#endif + } + + send[0] = 0x04; + send[1] = mute; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n"); + return changed; + } + changed = 1; + } + + spin_unlock_irqrestore(&cs4350_priv->lock, flags); + + return changed; +} + +static struct snd_kcontrol_new ubi32_cs4350_mute __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "PCM Playback Switch", + .info = ubi32_cs4350_mute_info, + .get = ubi32_cs4350_mute_get, + .put = ubi32_cs4350_mute_put, +}; + +/* + * snd_ubi32_cs4350_free + * Card private data free function + */ +void snd_ubi32_cs4350_free(struct snd_card *card) +{ + struct ubi32_snd_priv *ubi32_priv; + struct ubi32_cs4350_priv *cs4350_priv; + + ubi32_priv = card->private_data; + cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); + if (cs4350_priv) { + kfree(cs4350_priv); + } +} + +/* + * snd_ubi32_cs4350_dac_init + */ +static int snd_ubi32_cs4350_dac_init(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret; + char send[2]; + char recv[8]; + + /* + * Initialize the CS4350 DAC over the I2C interface + */ + snd_printk(KERN_INFO "Initializing CS4350 DAC\n"); + + /* + * Register 0x01: device/revid + */ + send[0] = 0x01; + ret = i2c_master_send(client, send, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed 1st attempt to write to CS4350 register 0x01\n"); + goto fail; + } + ret = i2c_master_recv(client, recv, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed initial read of CS4350 registers\n"); + goto fail; + } + snd_printk(KERN_INFO "CS4350 DAC Device/Rev: %08x\n", recv[0]); + + /* + * Register 0x02: Mode control + * I2S DIF[2:0] = 001, no De-Emphasis, Auto speed mode + */ + send[0] = 0x02; + send[1] = 0x10; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set CS4350 to I2S mode\n"); + goto fail; + } + + /* + * Register 0x05/0x06: Volume control + * Channel A volume set to 0 dB + * Channel B volume set to 0 dB + */ + send[0] = 0x05; + send[1] = 0x00; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n"); + goto fail; + } + + send[0] = 0x06; + send[1] = 0x00; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n"); + goto fail; + } + + /* + * Make sure the changes took place, this helps verify we are talking to + * the correct chip. + */ + send[0] = 0x81; + ret = i2c_master_send(client, send, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed to initiate readback\n"); + goto fail; + } + + ret = i2c_master_recv(client, recv, 8); + if (ret != 8) { + snd_printk(KERN_ERR "Failed second read of CS4350 registers\n"); + goto fail; + } + + if ((recv[1] != 0x10) || (recv[4] != 0x00) || (recv[5] != 0x00)) { + snd_printk(KERN_ERR "Failed to initialize CS4350 DAC\n"); + goto fail; + } + + snd_printk(KERN_INFO "CS4350 DAC Initialized\n"); + return 0; + +fail: + return -ENODEV; +} + +/* + * snd_ubi32_cs4350_i2c_probe + */ +static int snd_ubi32_cs4350_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct snd_card *card; + struct ubi32_snd_priv *ubi32_priv; + struct ubi32_cs4350_priv *cs4350_priv; + int err, ret; + struct platform_device *pdev; + + pdev = client->dev.platform_data; + if (!pdev) { + return -ENODEV; + } + + /* + * Initialize the CS4350 DAC + */ + ret = snd_ubi32_cs4350_dac_init(client, id); + if (ret < 0) { + /* + * Initialization failed. Propagate the error. + */ + return ret; + } + + /* + * Create a snd_card structure + */ + card = snd_card_new(index, "Ubi32-CS4350", THIS_MODULE, sizeof(struct ubi32_snd_priv)); + if (card == NULL) { + return -ENOMEM; + } + + card->private_free = snd_ubi32_cs4350_free; /* Not sure if correct */ + ubi32_priv = card->private_data; + + /* + * CS4350 DAC has a minimum sample rate of 30khz and an + * upper limit of 216khz for it's auto-detect. + */ + ubi32_priv->min_sample_rate = 30000; + ubi32_priv->max_sample_rate = 216000; + + /* + * Initialize the snd_card's private data structure + */ + ubi32_priv->card = card; + ubi32_priv->client = client; + + /* + * Create our private data structure + */ + cs4350_priv = kzalloc(sizeof(struct ubi32_cs4350_priv), GFP_KERNEL); + if (!cs4350_priv) { + snd_card_free(card); + return -ENOMEM; + } + snd_ubi32_priv_set_drv(ubi32_priv, cs4350_priv); + spin_lock_init(&cs4350_priv->lock); + + /* + * Initial volume is set to max by probe function + */ + cs4350_priv->volume[0] = 0xFF; + cs4350_priv->volume[1] = 0xFF; + + /* + * The CS4350 starts off unmuted (bit set = not muted) + */ + cs4350_priv->mute = 3; + + /* + * Create the new PCM instance + */ + err = snd_ubi32_pcm_probe(ubi32_priv, pdev); + if (err < 0) { + snd_card_free(card); + return err; /* What is err? Need to include correct file */ + } + + strcpy(card->driver, "Ubi32-CS4350"); + strcpy(card->shortname, "Ubi32-CS4350"); + snprintf(card->longname, sizeof(card->longname), + "%s at sendirq=%d.%d recvirq=%d.%d regs=%p", + card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx, + ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr); + + snd_card_set_dev(card, &client->dev); + + /* + * Set up the mixer components + */ + err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_volume, ubi32_priv)); + if (err) { + snd_printk(KERN_WARNING "Failed to add volume mixer control\n"); + } + err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_mute, ubi32_priv)); + if (err) { + snd_printk(KERN_WARNING "Failed to add mute mixer control\n"); + } + + /* + * Register the sound card + */ + if ((err = snd_card_register(card)) != 0) { + snd_printk(KERN_WARNING "snd_card_register error\n"); + } + + /* + * Store card for access from other methods + */ + i2c_set_clientdata(client, card); + + return 0; +} + +/* + * snd_ubi32_cs4350_i2c_remove + */ +static int __devexit snd_ubi32_cs4350_i2c_remove(struct i2c_client *client) +{ + struct snd_card *card; + struct ubi32_snd_priv *ubi32_priv; + + card = i2c_get_clientdata(client); + + ubi32_priv = card->private_data; + snd_ubi32_pcm_remove(ubi32_priv); + + snd_card_free(i2c_get_clientdata(client)); + i2c_set_clientdata(client, NULL); + + return 0; +} + +/* + * I2C driver description + */ +static struct i2c_driver snd_ubi32_cs4350_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .id_table = snd_ubi32_cs4350_id, + .probe = snd_ubi32_cs4350_i2c_probe, + .remove = __devexit_p(snd_ubi32_cs4350_i2c_remove), +}; + +/* + * Driver init + */ +static int __init snd_ubi32_cs4350_init(void) +{ + return i2c_add_driver(&snd_ubi32_cs4350_driver); +} +module_init(snd_ubi32_cs4350_init); + +/* + * snd_ubi32_cs4350_exit + */ +static void __exit snd_ubi32_cs4350_exit(void) +{ + i2c_del_driver(&snd_ubi32_cs4350_driver); +} +module_exit(snd_ubi32_cs4350_exit); + +/* + * Module properties + */ +MODULE_ALIAS("i2c:" DRIVER_NAME); +MODULE_AUTHOR("Patrick Tjin"); +MODULE_DESCRIPTION("Driver for Ubicom32 audio devices CS4350"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4384.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4384.c new file mode 100644 index 000000000..267926773 --- /dev/null +++ b/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4384.c @@ -0,0 +1,996 @@ +/* + * sound/ubicom32/ubi32-cs4384.c + * Interface to ubicom32 virtual audio peripheral - using CS4384 DAC + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ubi32.h" + +#define DRIVER_NAME "snd-ubi32-cs4384" + +/* + * Module properties + */ +static const struct i2c_device_id snd_ubi32_cs4384_id[] = { + {"cs4384", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ubicom32audio_id); + +static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ + +/* + * Mixer properties + */ +enum { + /* + * Be careful of changing the order of these IDs, they + * are used to index the volume array. + */ + SND_UBI32_CS4384_FRONT_ID, + SND_UBI32_CS4384_SURROUND_ID, + SND_UBI32_CS4384_CENTER_ID, + SND_UBI32_CS4384_LFE_ID, + SND_UBI32_CS4384_REAR_ID, + + /* + * This should be the last ID + */ + SND_UBI32_CS4384_LAST_ID, +}; +static const u8_t snd_ubi32_cs4384_ch_ofs[] = {0, 2, 4, 5, 6}; + +static const DECLARE_TLV_DB_SCALE(snd_ubi32_cs4384_db, -12750, 50, 0); + +#define snd_ubi32_cs4384_info_mute snd_ctl_boolean_stereo_info +#define snd_ubi32_cs4384_info_mute_mono snd_ctl_boolean_mono_info + +/* + * Mixer controls + */ +static int snd_ubi32_cs4384_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); +static int snd_ubi32_cs4384_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +static int snd_ubi32_cs4384_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +static int snd_ubi32_cs4384_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +static int snd_ubi32_cs4384_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); + +/* + * Make sure to update these if the structure below is changed + */ +#define SND_UBI32_MUTE_CTL_START 5 +#define SND_UBI32_MUTE_CTL_END 9 +static struct snd_kcontrol_new snd_ubi32_cs4384_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "Front Playback Volume", + .info = snd_ubi32_cs4384_info_volume, + .get = snd_ubi32_cs4384_get_volume, + .put = snd_ubi32_cs4384_put_volume, + .private_value = SND_UBI32_CS4384_FRONT_ID, + .tlv = { + .p = snd_ubi32_cs4384_db, + }, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "Surround Playback Volume", + .info = snd_ubi32_cs4384_info_volume, + .get = snd_ubi32_cs4384_get_volume, + .put = snd_ubi32_cs4384_put_volume, + .private_value = SND_UBI32_CS4384_SURROUND_ID, + .tlv = { + .p = snd_ubi32_cs4384_db, + }, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "Center Playback Volume", + .info = snd_ubi32_cs4384_info_volume, + .get = snd_ubi32_cs4384_get_volume, + .put = snd_ubi32_cs4384_put_volume, + .private_value = SND_UBI32_CS4384_CENTER_ID, + .tlv = { + .p = snd_ubi32_cs4384_db, + }, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "LFE Playback Volume", + .info = snd_ubi32_cs4384_info_volume, + .get = snd_ubi32_cs4384_get_volume, + .put = snd_ubi32_cs4384_put_volume, + .private_value = SND_UBI32_CS4384_LFE_ID, + .tlv = { + .p = snd_ubi32_cs4384_db, + }, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "Rear Playback Volume", + .info = snd_ubi32_cs4384_info_volume, + .get = snd_ubi32_cs4384_get_volume, + .put = snd_ubi32_cs4384_put_volume, + .private_value = SND_UBI32_CS4384_REAR_ID, + .tlv = { + .p = snd_ubi32_cs4384_db, + }, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "Front Playback Switch", + .info = snd_ubi32_cs4384_info_mute, + .get = snd_ubi32_cs4384_get_mute, + .put = snd_ubi32_cs4384_put_mute, + .private_value = SND_UBI32_CS4384_FRONT_ID, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "Surround Playback Switch", + .info = snd_ubi32_cs4384_info_mute, + .get = snd_ubi32_cs4384_get_mute, + .put = snd_ubi32_cs4384_put_mute, + .private_value = SND_UBI32_CS4384_SURROUND_ID, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "Center Playback Switch", + .info = snd_ubi32_cs4384_info_mute_mono, + .get = snd_ubi32_cs4384_get_mute, + .put = snd_ubi32_cs4384_put_mute, + .private_value = SND_UBI32_CS4384_CENTER_ID, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "LFE Playback Switch", + .info = snd_ubi32_cs4384_info_mute_mono, + .get = snd_ubi32_cs4384_get_mute, + .put = snd_ubi32_cs4384_put_mute, + .private_value = SND_UBI32_CS4384_LFE_ID, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "Rear Playback Switch", + .info = snd_ubi32_cs4384_info_mute, + .get = snd_ubi32_cs4384_get_mute, + .put = snd_ubi32_cs4384_put_mute, + .private_value = SND_UBI32_CS4384_REAR_ID, + }, +}; + +/* + * Our private data + */ +struct snd_ubi32_cs4384_priv { + /* + * Array of current volumes + * (L, R, SL, SR, C, LFE, RL, RR) + */ + uint8_t volume[8]; + + /* + * Bitmask of mutes + * MSB (RR, RL, LFE, C, SR, SL, R, L) LSB + */ + uint8_t mute; + + /* + * Array of controls + */ + struct snd_kcontrol *kctls[ARRAY_SIZE(snd_ubi32_cs4384_controls)]; + + /* + * Lock to protect our card + */ + spinlock_t lock; +}; + +/* + * snd_ubi32_cs4384_info_volume + */ +static int snd_ubi32_cs4384_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + unsigned int id = (unsigned int)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + if ((id != SND_UBI32_CS4384_LFE_ID) && + (id != SND_UBI32_CS4384_CENTER_ID)) { + uinfo->count = 2; + } + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 255; + return 0; +} + +/* + * snd_ubi32_cs4384_get_volume + */ +static int snd_ubi32_cs4384_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol); + struct snd_ubi32_cs4384_priv *cs4384_priv; + unsigned int id = (unsigned int)kcontrol->private_value; + int ch = snd_ubi32_cs4384_ch_ofs[id]; + unsigned long flags; + + if (id >= SND_UBI32_CS4384_LAST_ID) { + return -EINVAL; + } + + cs4384_priv = snd_ubi32_priv_get_drv(priv); + + spin_lock_irqsave(&cs4384_priv->lock, flags); + + ucontrol->value.integer.value[0] = cs4384_priv->volume[ch]; + if ((id != SND_UBI32_CS4384_LFE_ID) && + (id != SND_UBI32_CS4384_CENTER_ID)) { + ch++; + ucontrol->value.integer.value[1] = cs4384_priv->volume[ch]; + } + + spin_unlock_irqrestore(&cs4384_priv->lock, flags); + + return 0; +} + +/* + * snd_ubi32_cs4384_put_volume + */ +static int snd_ubi32_cs4384_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol); + struct i2c_client *client = (struct i2c_client *)priv->client; + struct snd_ubi32_cs4384_priv *cs4384_priv; + unsigned int id = (unsigned int)kcontrol->private_value; + int ch = snd_ubi32_cs4384_ch_ofs[id]; + unsigned long flags; + unsigned char send[3]; + int nch; + int ret = -EINVAL; + + if (id >= SND_UBI32_CS4384_LAST_ID) { + return -EINVAL; + } + + cs4384_priv = snd_ubi32_priv_get_drv(priv); + + spin_lock_irqsave(&cs4384_priv->lock, flags); + + send[0] = 0; + switch (id) { + case SND_UBI32_CS4384_REAR_ID: + send[0] = 0x06; + + /* + * Fall through + */ + + case SND_UBI32_CS4384_SURROUND_ID: + send[0] += 0x03; + + /* + * Fall through + */ + + case SND_UBI32_CS4384_FRONT_ID: + send[0] += 0x8B; + nch = 2; + send[1] = 255 - (ucontrol->value.integer.value[0] & 0xFF); + send[2] = 255 - (ucontrol->value.integer.value[1] & 0xFF); + cs4384_priv->volume[ch++] = send[1]; + cs4384_priv->volume[ch] = send[2]; + break; + + case SND_UBI32_CS4384_LFE_ID: + send[0] = 0x81; + + /* + * Fall through + */ + + case SND_UBI32_CS4384_CENTER_ID: + send[0] += 0x11; + nch = 1; + send[1] = 255 - (ucontrol->value.integer.value[0] & 0xFF); + cs4384_priv->volume[ch] = send[1]; + break; + + default: + spin_unlock_irqrestore(&cs4384_priv->lock, flags); + goto done; + + } + + /* + * Send the volume to the chip + */ + nch++; + ret = i2c_master_send(client, send, nch); + if (ret != nch) { + snd_printk(KERN_ERR "Failed to set volume on CS4384\n"); + } + +done: + spin_unlock_irqrestore(&cs4384_priv->lock, flags); + + return ret; +} + +/* + * snd_ubi32_cs4384_get_mute + */ +static int snd_ubi32_cs4384_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol); + struct snd_ubi32_cs4384_priv *cs4384_priv; + unsigned int id = (unsigned int)kcontrol->private_value; + int ch = snd_ubi32_cs4384_ch_ofs[id]; + unsigned long flags; + + if (id >= SND_UBI32_CS4384_LAST_ID) { + return -EINVAL; + } + + cs4384_priv = snd_ubi32_priv_get_drv(priv); + + spin_lock_irqsave(&cs4384_priv->lock, flags); + + ucontrol->value.integer.value[0] = !(cs4384_priv->mute & (1 << ch)); + + if ((id != SND_UBI32_CS4384_LFE_ID) && + (id != SND_UBI32_CS4384_CENTER_ID)) { + ch++; + ucontrol->value.integer.value[1] = !(cs4384_priv->mute & (1 << ch)); + } + + spin_unlock_irqrestore(&cs4384_priv->lock, flags); + + return 0; +} + +/* + * snd_ubi32_cs4384_put_mute + */ +static int snd_ubi32_cs4384_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol); + struct i2c_client *client = (struct i2c_client *)priv->client; + struct snd_ubi32_cs4384_priv *cs4384_priv; + unsigned int id = (unsigned int)kcontrol->private_value; + int ch = snd_ubi32_cs4384_ch_ofs[id]; + unsigned long flags; + unsigned char send[2]; + int ret = -EINVAL; + + if (id >= SND_UBI32_CS4384_LAST_ID) { + return -EINVAL; + } + + cs4384_priv = snd_ubi32_priv_get_drv(priv); + + spin_lock_irqsave(&cs4384_priv->lock, flags); + + if (ucontrol->value.integer.value[0]) { + cs4384_priv->mute &= ~(1 << ch); + } else { + cs4384_priv->mute |= (1 << ch); + } + + if ((id != SND_UBI32_CS4384_LFE_ID) && (id != SND_UBI32_CS4384_CENTER_ID)) { + ch++; + if (ucontrol->value.integer.value[1]) { + cs4384_priv->mute &= ~(1 << ch); + } else { + cs4384_priv->mute |= (1 << ch); + } + } + + /* + * Update the chip's mute reigster + */ + send[0] = 0x09; + send[1] = cs4384_priv->mute; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set mute on CS4384\n"); + } + + spin_unlock_irqrestore(&cs4384_priv->lock, flags); + + return ret; +} + +/* + * snd_ubi32_cs4384_mixer + * Setup the mixer controls + */ +static int __devinit snd_ubi32_cs4384_mixer(struct ubi32_snd_priv *priv) +{ + struct snd_card *card = priv->card; + struct snd_ubi32_cs4384_priv *cs4384_priv; + int i; + + cs4384_priv = snd_ubi32_priv_get_drv(priv); + for (i = 0; i < ARRAY_SIZE(snd_ubi32_cs4384_controls); i++) { + int err; + + cs4384_priv->kctls[i] = snd_ctl_new1(&snd_ubi32_cs4384_controls[i], priv); + err = snd_ctl_add(card, cs4384_priv->kctls[i]); + if (err) { + snd_printk(KERN_WARNING "Failed to add control %d\n", i); + return err; + } + } + return 0; +} + +/* + * snd_ubi32_cs4384_free + * Card private data free function + */ +void snd_ubi32_cs4384_free(struct snd_card *card) +{ + struct snd_ubi32_cs4384_priv *cs4384_priv; + struct ubi32_snd_priv *ubi32_priv; + + ubi32_priv = card->private_data; + cs4384_priv = snd_ubi32_priv_get_drv(ubi32_priv); + if (cs4384_priv) { + kfree(cs4384_priv); + } +} + +/* + * snd_ubi32_cs4384_setup_mclk + */ +static int snd_ubi32_cs4384_setup_mclk(struct ubi32_cs4384_platform_data *pdata) +{ + struct ubicom32_io_port *ioa = (struct ubicom32_io_port *)RA; + struct ubicom32_io_port *ioc = (struct ubicom32_io_port *)RC; + struct ubicom32_io_port *iod = (struct ubicom32_io_port *)RD; + struct ubicom32_io_port *ioe = (struct ubicom32_io_port *)RE; + struct ubicom32_io_port *ioh = (struct ubicom32_io_port *)RH; + unsigned int ctl0; + unsigned int ctlx; + unsigned int div; + + div = pdata->mclk_entries[0].div; + + ctl0 = (1 << 13); + ctlx = ((div - 1) << 16) | (div / 2); + + switch (pdata->mclk_src) { + case UBI32_CS4384_MCLK_PWM_0: + ioc->function |= 2; + ioc->ctl0 |= ctl0; + ioc->ctl1 = ctlx; + if (!ioa->function) { + ioa->function = 3; + } + return 0; + + case UBI32_CS4384_MCLK_PWM_1: + ioc->function |= 2; + ioc->ctl0 |= ctl0 << 16; + ioc->ctl2 = ctlx; + if (!ioe->function) { + ioe->function = 3; + } + return 0; + + case UBI32_CS4384_MCLK_PWM_2: + ioh->ctl0 |= ctl0; + ioh->ctl1 = ctlx; + if (!iod->function) { + iod->function = 3; + } + return 0; + + case UBI32_CS4384_MCLK_CLKDIV_1: + ioa->gpio_mask &= (1 << 7); + ioa->ctl1 &= ~(0x7F << 14); + ioa->ctl1 |= ((div - 1) << 14); + return 0; + + case UBI32_CS4384_MCLK_OTHER: + return 0; + } + + return 1; +} + +/* + * snd_ubi32_cs4384_set_rate + */ +static int snd_ubi32_cs4384_set_rate(struct ubi32_snd_priv *priv, int rate) +{ + struct ubi32_cs4384_platform_data *cpd = priv->pdata->priv_data; + struct ubicom32_io_port *ioa = (struct ubicom32_io_port *)RA; + struct ubicom32_io_port *ioc = (struct ubicom32_io_port *)RC; + struct ubicom32_io_port *ioh = (struct ubicom32_io_port *)RH; + unsigned int ctl; + unsigned int div = 0; + const u16_t mult[] = {64, 96, 128, 192, 256, 384, 512, 768, 1024}; + int i; + int j; + + + for (i = 0; i < sizeof(mult) / sizeof(u16_t); i++) { + for (j = 0; j < cpd->n_mclk; j++) { + if (((unsigned int)rate * (unsigned int)mult[i]) == + cpd->mclk_entries[j].rate) { + div = cpd->mclk_entries[j].div; + break; + } + } + } + + ctl = ((div - 1) << 16) | (div / 2); + + switch (cpd->mclk_src) { + case UBI32_CS4384_MCLK_PWM_0: + ioc->ctl1 = ctl; + return 0; + + case UBI32_CS4384_MCLK_PWM_1: + ioc->ctl2 = ctl; + return 0; + + case UBI32_CS4384_MCLK_PWM_2: + ioh->ctl1 = ctl; + return 0; + + case UBI32_CS4384_MCLK_CLKDIV_1: + ioa->ctl1 &= ~(0x7F << 14); + ioa->ctl1 |= ((div - 1) << 14); + return 0; + + case UBI32_CS4384_MCLK_OTHER: + return 0; + } + + return 1; +} + +/* + * snd_ubi32_cs4384_set_channels + * Mute unused channels + */ +static int snd_ubi32_cs4384_set_channels(struct ubi32_snd_priv *priv, int channels) +{ + struct i2c_client *client = (struct i2c_client *)priv->client; + struct snd_ubi32_cs4384_priv *cs4384_priv; + unsigned char send[2]; + int ret; + int i; + unsigned long flags; + + /* + * Only support 0, 2, 4, 6, 8 channels + */ + if ((channels > 8) || (channels & 1)) { + return -EINVAL; + } + + cs4384_priv = snd_ubi32_priv_get_drv(priv); + spin_lock_irqsave(&cs4384_priv->lock, flags); + + /* + * Address 09h, Mute control + */ + send[0] = 0x09; + send[1] = (unsigned char)(0xFF << channels); + + ret = i2c_master_send(client, send, 2); + + spin_unlock_irqrestore(&cs4384_priv->lock, flags); + + /* + * Notify the system that we changed the mutes + */ + cs4384_priv->mute = (unsigned char)(0xFF << channels); + + for (i = SND_UBI32_MUTE_CTL_START; i < SND_UBI32_MUTE_CTL_END; i++) { + snd_ctl_notify(priv->card, SNDRV_CTL_EVENT_MASK_VALUE, + &cs4384_priv->kctls[i]->id); + } + + if (ret != 2) { + return -ENXIO; + } + + return 0; +} + +/* + * snd_ubi32_cs4384_dac_init + */ +static int snd_ubi32_cs4384_dac_init(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret; + unsigned char send[2]; + unsigned char recv[2]; + + /* + * Initialize the CS4384 DAC over the I2C interface + */ + snd_printk(KERN_INFO "Initializing CS4384 DAC\n"); + + /* + * Register 0x01: device/revid + */ + send[0] = 0x01; + ret = i2c_master_send(client, send, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed 1st attempt to write to CS4384 register 0x01\n"); + goto fail; + } + ret = i2c_master_recv(client, recv, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed initial read of CS4384 registers\n"); + goto fail; + } + snd_printk(KERN_INFO "CS4384 DAC Device/Rev: %08x\n", recv[0]); + + /* + * Register 0x02: Mode Control 1 + * Control Port Enable, PCM, All DACs enabled, Power Down + */ + send[0] = 0x02; + send[1] = 0x81; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set CPEN CS4384\n"); + goto fail; + } + + /* + * Register 0x08: Ramp and Mute + * RMP_UP, RMP_DN, PAMUTE, DAMUTE + */ + send[0] = 0x08; + send[1] = 0xBC; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set CPEN CS4384\n"); + goto fail; + } + + /* + * Register 0x03: PCM Control + * I2S DIF[3:0] = 0001, no De-Emphasis, Auto speed mode + */ + send[0] = 0x03; + send[1] = 0x13; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to set CS4384 to I2S mode\n"); + goto fail; + } + + /* + * Register 0x0B/0x0C: Volume control A1/B1 + * Register 0x0E/0x0F: Volume control A2/B2 + * Register 0x11/0x12: Volume control A3/B3 + * Register 0x14/0x15: Volume control A4/B4 + */ + send[0] = 0x80 | 0x0B; + send[1] = 0x00; + send[2] = 0x00; + ret = i2c_master_send(client, send, 3); + if (ret != 3) { + snd_printk(KERN_ERR "Failed to set ch1 volume on CS4384\n"); + goto fail; + } + + send[0] = 0x80 | 0x0E; + send[1] = 0x00; + send[2] = 0x00; + ret = i2c_master_send(client, send, 3); + if (ret != 3) { + snd_printk(KERN_ERR "Failed to set ch2 volume on CS4384\n"); + goto fail; + } + + send[0] = 0x80 | 0x11; + send[1] = 0x00; + send[2] = 0x00; + ret = i2c_master_send(client, send, 3); + if (ret != 3) { + snd_printk(KERN_ERR "Failed to set ch3 volume on CS4384\n"); + goto fail; + } + + send[0] = 0x80 | 0x14; + send[1] = 0x00; + send[2] = 0x00; + ret = i2c_master_send(client, send, 3); + if (ret != 3) { + snd_printk(KERN_ERR "Failed to set ch4 volume on CS4384\n"); + goto fail; + } + + /* + * Register 09h: Mute control + * Mute all (we will unmute channels as needed) + */ + send[0] = 0x09; + send[1] = 0xFF; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to power up CS4384\n"); + goto fail; + } + + /* + * Register 0x02: Mode Control 1 + * Control Port Enable, PCM, All DACs enabled, Power Up + */ + send[0] = 0x02; + send[1] = 0x80; + ret = i2c_master_send(client, send, 2); + if (ret != 2) { + snd_printk(KERN_ERR "Failed to power up CS4384\n"); + goto fail; + } + + /* + * Make sure the changes took place, this helps verify we are talking to + * the correct chip. + */ + send[0] = 0x80 | 0x03; + ret = i2c_master_send(client, send, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed to initiate readback\n"); + goto fail; + } + + ret = i2c_master_recv(client, recv, 1); + if (ret != 1) { + snd_printk(KERN_ERR "Failed second read of CS4384 registers\n"); + goto fail; + } + + if (recv[0] != 0x13) { + snd_printk(KERN_ERR "Failed to initialize CS4384 DAC\n"); + goto fail; + } + + snd_printk(KERN_INFO "CS4384 DAC Initialized\n"); + return 0; + +fail: + return -ENODEV; +} + +/* + * snd_ubi32_cs4384_i2c_probe + */ +static int snd_ubi32_cs4384_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct snd_card *card; + struct ubi32_snd_priv *ubi32_priv; + int err, ret; + struct platform_device *pdev; + struct ubi32_cs4384_platform_data *pdata; + struct snd_ubi32_cs4384_priv *cs4384_priv; + + /* + * pdev is audio device + */ + pdev = client->dev.platform_data; + if (!pdev) { + return -ENODEV; + } + + /* + * pdev->dev.platform_data is ubi32-pcm platform_data + */ + pdata = audio_device_priv(pdev); + if (!pdata) { + return -ENODEV; + } + + /* + * Initialize the CS4384 DAC + */ + ret = snd_ubi32_cs4384_dac_init(client, id); + if (ret < 0) { + /* + * Initialization failed. Propagate the error. + */ + return ret; + } + + if (snd_ubi32_cs4384_setup_mclk(pdata)) { + return -EINVAL; + } + + /* + * Create a snd_card structure + */ + card = snd_card_new(index, "Ubi32-CS4384", THIS_MODULE, sizeof(struct ubi32_snd_priv)); + if (card == NULL) { + return -ENOMEM; + } + + card->private_free = snd_ubi32_cs4384_free; + ubi32_priv = card->private_data; + + /* + * Initialize the snd_card's private data structure + */ + ubi32_priv->card = card; + ubi32_priv->client = client; + ubi32_priv->set_channels = snd_ubi32_cs4384_set_channels; + ubi32_priv->set_rate = snd_ubi32_cs4384_set_rate; + + /* + * CS4384 DAC has a minimum sample rate of 4khz and an + * upper limit of 216khz for it's auto-detect. + */ + ubi32_priv->min_sample_rate = 4000; + ubi32_priv->max_sample_rate = 216000; + + /* + * Create our private data (to manage volume, etc) + */ + cs4384_priv = kzalloc(sizeof(struct snd_ubi32_cs4384_priv), GFP_KERNEL); + if (!cs4384_priv) { + snd_card_free(card); + return -ENOMEM; + } + snd_ubi32_priv_set_drv(ubi32_priv, cs4384_priv); + spin_lock_init(&cs4384_priv->lock); + + /* + * We start off all muted and max volume + */ + cs4384_priv->mute = 0xFF; + memset(cs4384_priv->volume, 0xFF, 8); + + /* + * Create the new PCM instance + */ + err = snd_ubi32_pcm_probe(ubi32_priv, pdev); + if (err < 0) { + snd_card_free(card); + return err; /* What is err? Need to include correct file */ + } + + strcpy(card->driver, "Ubi32-CS4384"); + strcpy(card->shortname, "Ubi32-CS4384"); + snprintf(card->longname, sizeof(card->longname), + "%s at sendirq=%d.%d recvirq=%d.%d regs=%p", + card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx, + ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr); + + snd_card_set_dev(card, &client->dev); + + /* + * Set up the mixer + */ + snd_ubi32_cs4384_mixer(ubi32_priv); + + /* + * Register the sound card + */ + if ((err = snd_card_register(card)) != 0) { + snd_printk(KERN_INFO "snd_card_register error\n"); + } + + /* + * Store card for access from other methods + */ + i2c_set_clientdata(client, card); + + return 0; +} + +/* + * snd_ubi32_cs4384_i2c_remove + */ +static int __devexit snd_ubi32_cs4384_i2c_remove(struct i2c_client *client) +{ + struct snd_card *card; + struct ubi32_snd_priv *ubi32_priv; + + card = i2c_get_clientdata(client); + + ubi32_priv = card->private_data; + snd_ubi32_pcm_remove(ubi32_priv); + + snd_card_free(i2c_get_clientdata(client)); + i2c_set_clientdata(client, NULL); + + return 0; +} + +/* + * I2C driver description + */ +static struct i2c_driver snd_ubi32_cs4384_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .id_table = snd_ubi32_cs4384_id, + .probe = snd_ubi32_cs4384_i2c_probe, + .remove = __devexit_p(snd_ubi32_cs4384_i2c_remove), +}; + +/* + * Driver init + */ +static int __init snd_ubi32_cs4384_init(void) +{ + return i2c_add_driver(&snd_ubi32_cs4384_driver); +} +module_init(snd_ubi32_cs4384_init); + +/* + * snd_ubi32_cs4384_exit + */ +static void __exit snd_ubi32_cs4384_exit(void) +{ + i2c_del_driver(&snd_ubi32_cs4384_driver); +} +module_exit(snd_ubi32_cs4384_exit); + +/* + * Module properties + */ +MODULE_ALIAS("i2c:" DRIVER_NAME); +MODULE_AUTHOR("Patrick Tjin"); +MODULE_DESCRIPTION("Driver for Ubicom32 audio devices CS4384"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic-capture.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic-capture.c new file mode 100644 index 000000000..a911cc6a1 --- /dev/null +++ b/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic-capture.c @@ -0,0 +1,167 @@ +/* + * sound/ubicom32/ubi32-generic-capture.c + * Interface to ubicom32 virtual audio peripheral + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include "ubi32.h" + +#define DRIVER_NAME "snd-ubi32-generic-capture" + +/* + * Module properties + */ +static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ + +/* + * Card private data free function + */ +void snd_ubi32_generic_capture_free(struct snd_card *card) +{ + /* + * Free all the fields in the snd_ubi32_priv struct + */ + // Nothing to free at this time because ubi32_priv just maintains pointers +} + +/* + * Ubicom audio driver probe() method. Args change depending on whether we use + * platform_device or i2c_device. + */ +static int snd_ubi32_generic_capture_probe(struct platform_device *dev) +{ + struct snd_card *card; + struct ubi32_snd_priv *ubi32_priv; + int err; + + /* + * Create a snd_card structure + */ + card = snd_card_new(index, "Ubi32-Generic-C", THIS_MODULE, sizeof(struct ubi32_snd_priv)); + + if (card == NULL) { + return -ENOMEM; + } + + card->private_free = snd_ubi32_generic_capture_free; /* Not sure if correct */ + ubi32_priv = card->private_data; + + /* + * Initialize the snd_card's private data structure + */ + ubi32_priv->card = card; + ubi32_priv->is_capture = 1; + + /* + * Create the new PCM instance + */ + err = snd_ubi32_pcm_probe(ubi32_priv, dev); + if (err < 0) { + snd_card_free(card); + return err; + } + + strcpy(card->driver, "Ubi32-Generic-C"); + strcpy(card->shortname, "Ubi32-Generic-C"); + snprintf(card->longname, sizeof(card->longname), + "%s at sendirq=%d.%d recvirq=%d.%d regs=%p", + card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx, + ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr); + + snd_card_set_dev(card, &dev->dev); + + /* Register the sound card */ + if ((err = snd_card_register(card)) != 0) { + snd_printk(KERN_INFO "snd_card_register error\n"); + } + + /* Store card for access from other methods */ + platform_set_drvdata(dev, card); + + return 0; +} + +/* + * Ubicom audio driver remove() method + */ +static int __devexit snd_ubi32_generic_capture_remove(struct platform_device *dev) +{ + struct snd_card *card; + struct ubi32_snd_priv *ubi32_priv; + + card = platform_get_drvdata(dev); + ubi32_priv = card->private_data; + snd_ubi32_pcm_remove(ubi32_priv); + + snd_card_free(platform_get_drvdata(dev)); + platform_set_drvdata(dev, NULL); + return 0; +} + +/* + * Platform driver definition + */ +static struct platform_driver snd_ubi32_generic_capture_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = snd_ubi32_generic_capture_probe, + .remove = __devexit_p(snd_ubi32_generic_capture_remove), +}; + +/* + * snd_ubi32_generic_capture_init + */ +static int __init snd_ubi32_generic_capture_init(void) +{ + return platform_driver_register(&snd_ubi32_generic_capture_driver); +} +module_init(snd_ubi32_generic_capture_init); + +/* + * snd_ubi32_generic_capture_exit + */ +static void __exit snd_ubi32_generic_capture_exit(void) +{ + platform_driver_unregister(&snd_ubi32_generic_capture_driver); +} +module_exit(snd_ubi32_generic_capture_exit); + +/* + * Module properties + */ +//#if defined(CONFIG_SND_UBI32_AUDIO_I2C) +//MODULE_ALIAS("i2c:snd-ubi32"); +//#endif +MODULE_AUTHOR("Patrick Tjin"); +MODULE_DESCRIPTION("Driver for Ubicom32 audio devices"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic.c new file mode 100644 index 000000000..eee6066ce --- /dev/null +++ b/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic.c @@ -0,0 +1,166 @@ +/* + * sound/ubicom32/ubi32-generic.c + * Interface to ubicom32 virtual audio peripheral + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include "ubi32.h" + +#define DRIVER_NAME "snd-ubi32-generic" + +/* + * Module properties + */ +static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ + +/* + * Card private data free function + */ +void snd_ubi32_generic_free(struct snd_card *card) +{ + /* + * Free all the fields in the snd_ubi32_priv struct + */ + // Nothing to free at this time because ubi32_priv just maintains pointers +} + +/* + * Ubicom audio driver probe() method. Args change depending on whether we use + * platform_device or i2c_device. + */ +static int snd_ubi32_generic_probe(struct platform_device *dev) +{ + struct snd_card *card; + struct ubi32_snd_priv *ubi32_priv; + int err; + + /* + * Create a snd_card structure + */ + card = snd_card_new(index, "Ubi32-Generic", THIS_MODULE, sizeof(struct ubi32_snd_priv)); + + if (card == NULL) { + return -ENOMEM; + } + + card->private_free = snd_ubi32_generic_free; /* Not sure if correct */ + ubi32_priv = card->private_data; + + /* + * Initialize the snd_card's private data structure + */ + ubi32_priv->card = card; + + /* + * Create the new PCM instance + */ + err = snd_ubi32_pcm_probe(ubi32_priv, dev); + if (err < 0) { + snd_card_free(card); + return err; + } + + strcpy(card->driver, "Ubi32-Generic"); + strcpy(card->shortname, "Ubi32-Generic"); + snprintf(card->longname, sizeof(card->longname), + "%s at sendirq=%d.%d recvirq=%d.%d regs=%p", + card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx, + ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr); + + snd_card_set_dev(card, &dev->dev); + + /* Register the sound card */ + if ((err = snd_card_register(card)) != 0) { + snd_printk(KERN_INFO "snd_card_register error\n"); + } + + /* Store card for access from other methods */ + platform_set_drvdata(dev, card); + + return 0; +} + +/* + * Ubicom audio driver remove() method + */ +static int __devexit snd_ubi32_generic_remove(struct platform_device *dev) +{ + struct snd_card *card; + struct ubi32_snd_priv *ubi32_priv; + + card = platform_get_drvdata(dev); + ubi32_priv = card->private_data; + snd_ubi32_pcm_remove(ubi32_priv); + + snd_card_free(platform_get_drvdata(dev)); + platform_set_drvdata(dev, NULL); + return 0; +} + +/* + * Platform driver definition + */ +static struct platform_driver snd_ubi32_generic_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = snd_ubi32_generic_probe, + .remove = __devexit_p(snd_ubi32_generic_remove), +}; + +/* + * snd_ubi32_generic_init + */ +static int __init snd_ubi32_generic_init(void) +{ + return platform_driver_register(&snd_ubi32_generic_driver); +} +module_init(snd_ubi32_generic_init); + +/* + * snd_ubi32_generic_exit + */ +static void __exit snd_ubi32_generic_exit(void) +{ + platform_driver_unregister(&snd_ubi32_generic_driver); +} +module_exit(snd_ubi32_generic_exit); + +/* + * Module properties + */ +//#if defined(CONFIG_SND_UBI32_AUDIO_I2C) +//MODULE_ALIAS("i2c:snd-ubi32"); +//#endif +MODULE_AUTHOR("Aaron Jow, Patrick Tjin"); +MODULE_DESCRIPTION("Driver for Ubicom32 audio devices"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-pcm.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-pcm.c new file mode 100644 index 000000000..2bc300b85 --- /dev/null +++ b/target/linux/ubicom32/files/sound/ubicom32/ubi32-pcm.c @@ -0,0 +1,711 @@ +/* + * sound/ubicom32/ubi32-pcm.c + * Interface to ubicom32 virtual audio peripheral + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ubi32.h" + +struct ubi32_snd_runtime_data { + dma_addr_t dma_buffer; /* Physical address of DMA buffer */ + dma_addr_t dma_buffer_end; /* First address beyond end of DMA buffer */ + size_t period_size; + dma_addr_t period_ptr; /* Physical address of next period */ + unsigned int flags; +}; + +static void snd_ubi32_vp_int_set(struct snd_pcm *pcm) +{ + struct ubi32_snd_priv *ubi32_priv = pcm->private_data; + ubi32_priv->ar->int_req |= (1 << ubi32_priv->irq_idx); + ubicom32_set_interrupt(ubi32_priv->tx_irq); +} + +static snd_pcm_uframes_t snd_ubi32_pcm_pointer(struct snd_pcm_substream *substream) +{ + + struct ubi32_snd_priv *ubi32_priv = snd_pcm_substream_chip(substream); + struct audio_dev_regs *adr = ubi32_priv->adr; + struct snd_pcm_runtime *runtime = substream->runtime; + struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data; + + dma_addr_t read_pos; + + snd_pcm_uframes_t frames; + if (!adr->primary_os_buffer_ptr) { + /* + * If primary_os_buffer_ptr is NULL (e.g. right after the HW is started or + * when the HW is stopped), then handle this case separately. + */ + return 0; + } + + read_pos = (dma_addr_t)adr->primary_os_buffer_ptr; + frames = bytes_to_frames(runtime, read_pos - ubi32_rd->dma_buffer); + if (frames == runtime->buffer_size) { + frames = 0; + } + return frames; +} + +/* + * Audio trigger + */ +static int snd_ubi32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data; + struct audio_dev_regs *adr = ubi32_priv->adr; + struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data; + int ret = 0; + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "snd_ubi32_pcm_trigger cmd=%d=", cmd); +#endif + + if (adr->command != AUDIO_CMD_NONE) { + snd_printk(KERN_WARNING "Can't send command to audio device at this time\n"); + // Set a timer to call this function back later. How to do this? + return 0; + } + + /* + * Set interrupt flag to indicate that we interrupted audio device + * to send a command + */ + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "START\n"); +#endif + /* + * Ready the DMA transfer + */ + ubi32_rd->period_ptr = ubi32_rd->dma_buffer; + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "trigger period_ptr=%lx\n", (unsigned long)ubi32_rd->period_ptr); +#endif + adr->dma_xfer_requests[0].ptr = (void *)ubi32_rd->period_ptr; + adr->dma_xfer_requests[0].ctr = ubi32_rd->period_size; + adr->dma_xfer_requests[0].active = 1; + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "xfer_request 0 ptr=0x%x ctr=%u\n", ubi32_rd->period_ptr, ubi32_rd->period_size); +#endif + + ubi32_rd->period_ptr += ubi32_rd->period_size; + adr->dma_xfer_requests[1].ptr = (void *)ubi32_rd->period_ptr; + adr->dma_xfer_requests[1].ctr = ubi32_rd->period_size; + adr->dma_xfer_requests[1].active = 1; + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "xfer_request 1 ptr=0x%x ctr=%u\n", ubi32_rd->period_ptr, ubi32_rd->period_size); +#endif + + /* + * Tell the VP that we want to begin playback by filling in the + * command field and then interrupting the audio VP + */ + adr->int_flags |= AUDIO_INT_FLAG_COMMAND; + adr->command = AUDIO_CMD_START; + snd_ubi32_vp_int_set(substream->pcm); + break; + + case SNDRV_PCM_TRIGGER_STOP: + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "STOP\n"); +#endif + + /* + * Tell the VP that we want to stop playback by filling in the + * command field and then interrupting the audio VP + */ + adr->int_flags |= AUDIO_INT_FLAG_COMMAND; + adr->command = AUDIO_CMD_STOP; + snd_ubi32_vp_int_set(substream->pcm); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "PAUSE_PUSH\n"); +#endif + + /* + * Tell the VP that we want to pause playback by filling in the + * command field and then interrupting the audio VP + */ + adr->int_flags |= AUDIO_INT_FLAG_COMMAND; + adr->command = AUDIO_CMD_PAUSE; + snd_ubi32_vp_int_set(substream->pcm); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "PAUSE_RELEASE\n"); +#endif + /* + * Tell the VP that we want to resume paused playback by filling + * in the command field and then interrupting the audio VP + */ + adr->int_flags |= AUDIO_INT_FLAG_COMMAND; + adr->command = AUDIO_CMD_RESUME; + snd_ubi32_vp_int_set(substream->pcm); + break; + + default: + snd_printk(KERN_WARNING "Unhandled trigger\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +/* + * Prepare to transfer an audio stream to the codec + */ +static int snd_ubi32_pcm_prepare(struct snd_pcm_substream *substream) +{ + /* + * Configure registers and setup the runtime instance for DMA transfers + */ + struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data; + struct audio_dev_regs *adr = ubi32_priv->adr; + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "snd_ubi32_pcm_prepare: sending STOP command to audio device\n"); +#endif + + /* + * Make sure the audio device is stopped + */ + + /* + * Set interrupt flag to indicate that we interrupted audio device + * to send a command + */ + adr->int_flags |= AUDIO_INT_FLAG_COMMAND; + adr->command = AUDIO_CMD_STOP; + snd_ubi32_vp_int_set(substream->pcm); + + return 0; +} + +/* + * Allocate DMA buffers from preallocated memory. + * Preallocation was done in snd_ubi32_pcm_new() + */ +static int snd_ubi32_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data; + struct audio_dev_regs *adr = ubi32_priv->adr; + struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data; + + /* + * Use pre-allocated memory from ubi32_snd_pcm_new() to satisfy + * this memory request. + */ + int ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (ret < 0) { + return ret; + } + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "snd_ubi32_pcm_hw_params\n"); +#endif + + if (!(adr->channel_mask & (1 << params_channels(hw_params)))) { + snd_printk(KERN_INFO "snd_ubi32_pcm_hw_params unsupported number of channels %d mask %08x\n", params_channels(hw_params), adr->channel_mask); + return -EINVAL; + } + + if (ubi32_priv->set_channels) { + int ret = ubi32_priv->set_channels(ubi32_priv, params_channels(hw_params)); + if (ret) { + snd_printk(KERN_WARNING "Unable to set channels to %d, ret=%d\n", params_channels(hw_params), ret); + return ret; + } + } + + if (ubi32_priv->set_rate) { + int ret = ubi32_priv->set_rate(ubi32_priv, params_rate(hw_params)); + if (ret) { + snd_printk(KERN_WARNING "Unable to set rate to %d, ret=%d\n", params_rate(hw_params), ret); + return ret; + } + } + + if (ubi32_priv->pdata->set_rate) { + int ret = ubi32_priv->pdata->set_rate(ubi32_priv->pdata->appdata, params_rate(hw_params)); + if (ret) { + snd_printk(KERN_WARNING "Unable to set rate to %d, ret=%d\n", params_rate(hw_params), ret); + return ret; + } + } + + if (adr->command != AUDIO_CMD_NONE) { + snd_printk(KERN_WARNING "snd_ubi32_pcm_hw_params: tio busy\n"); + return -EAGAIN; + } + + if (params_format(hw_params) == SNDRV_PCM_FORMAT_S16_LE) { + adr->flags |= CMD_START_FLAG_LE; + } else { + adr->flags &= ~CMD_START_FLAG_LE; + } + adr->channels = params_channels(hw_params); + adr->sample_rate = params_rate(hw_params); + adr->command = AUDIO_CMD_SETUP; + adr->int_flags |= AUDIO_INT_FLAG_COMMAND; + snd_ubi32_vp_int_set(substream->pcm); + + /* + * Wait for the command to complete + */ + while (adr->command != AUDIO_CMD_NONE) { + udelay(1); + } + + /* + * Put the DMA info into the DMA descriptor that we will + * use to do transfers to our audio VP "hardware" + */ + + /* + * Mark both DMA transfers as not ready/inactive + */ + adr->dma_xfer_requests[0].active = 0; + adr->dma_xfer_requests[1].active = 0; + + /* + * Put the location of the buffer into the runtime data instance + */ + ubi32_rd->dma_buffer = (dma_addr_t)runtime->dma_area; + ubi32_rd->dma_buffer_end = (dma_addr_t)(runtime->dma_area + runtime->dma_bytes); + + /* + * Get the period size + */ + ubi32_rd->period_size = params_period_bytes(hw_params); + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "DMA for ubi32 audio initialized dma_area=0x%x dma_bytes=%d, period_size=%d\n", (unsigned int)runtime->dma_area, (unsigned int)runtime->dma_bytes, ubi32_rd->period_size); + snd_printk(KERN_INFO "Private buffer ubi32_rd: dma_buffer=0x%x dma_buffer_end=0x%x ret=%d\n", ubi32_rd->dma_buffer, ubi32_rd->dma_buffer_end, ret); +#endif + + return ret; +} + +/* + * This is the reverse of snd_ubi32_pcm_hw_params + */ +static int snd_ubi32_pcm_hw_free(struct snd_pcm_substream *substream) +{ +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "snd_ubi32_pcm_hw_free\n"); +#endif + return snd_pcm_lib_free_pages(substream); +} + +/* + * Audio virtual peripheral capabilities (capture and playback are identical) + */ +static struct snd_pcm_hardware snd_ubi32_pcm_hw = +{ + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), + .buffer_bytes_max = (64*1024), + .period_bytes_min = 64, + .period_bytes_max = 8184,//8184,//8176, + .periods_min = 2, + .periods_max = 255, + .fifo_size = 0, // THIS IS IGNORED BY ALSA +}; + +/* + * We fill this in later + */ +static struct snd_pcm_hw_constraint_list ubi32_pcm_rates; + +/* + * snd_ubi32_pcm_close + */ +static int snd_ubi32_pcm_close(struct snd_pcm_substream *substream) +{ + /* Disable codec, stop DMA, free private data structures */ + //struct ubi32_snd_priv *ubi32_priv = snd_pcm_substream_chip(substream); + struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data; + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "snd_ubi32_pcm_close\n"); +#endif + + substream->runtime->private_data = NULL; + + kfree(ubi32_rd); + + return 0; +} + +/* + * snd_ubi32_pcm_open + */ +static int snd_ubi32_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct ubi32_snd_runtime_data *ubi32_rd; + int ret = 0; + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "ubi32 pcm open\n"); +#endif + + /* Associate capabilities with component */ + runtime->hw = snd_ubi32_pcm_hw; + + /* + * Inform ALSA about constraints of the audio device + */ + ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &ubi32_pcm_rates); + if (ret < 0) { + snd_printk(KERN_INFO "invalid rate\n"); + goto out; + } + + /* Force the buffer size to be an integer multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + snd_printk(KERN_INFO "invalid period\n"); + goto out; + } + /* Initialize structures/registers */ + ubi32_rd = kzalloc(sizeof(struct ubi32_snd_runtime_data), GFP_KERNEL); + if (ubi32_rd == NULL) { + ret = -ENOMEM; + goto out; + } + + runtime->private_data = ubi32_rd; + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "snd_ubi32_pcm_open returned 0\n"); +#endif + + return 0; +out: +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "snd_ubi32_pcm_open returned %d\n", ret); +#endif + + return ret; +} + +static struct snd_pcm_ops snd_ubi32_pcm_ops = { + .open = snd_ubi32_pcm_open, /* Open */ + .close = snd_ubi32_pcm_close, /* Close */ + .ioctl = snd_pcm_lib_ioctl, /* Generic IOCTL handler */ + .hw_params = snd_ubi32_pcm_hw_params, /* Hardware parameters/capabilities */ + .hw_free = snd_ubi32_pcm_hw_free, /* Free function for hw_params */ + .prepare = snd_ubi32_pcm_prepare, + .trigger = snd_ubi32_pcm_trigger, + .pointer = snd_ubi32_pcm_pointer, +}; + +/* + * Interrupt handler that gets called when the audio device + * interrupts Linux + */ +static irqreturn_t snd_ubi32_pcm_interrupt(int irq, void *appdata) +{ + struct snd_pcm *pcm = (struct snd_pcm *)appdata; + struct ubi32_snd_priv *ubi32_priv = pcm->private_data; + struct audio_dev_regs *adr = ubi32_priv->adr; + struct snd_pcm_substream *substream; + struct ubi32_snd_runtime_data *ubi32_rd; + int dma_to_fill = 0; + + /* + * Check to see if the interrupt is for us + */ + if (!(ubi32_priv->ar->int_status & (1 << ubi32_priv->irq_idx))) { + return IRQ_NONE; + } + + /* + * Clear the interrupt + */ + ubi32_priv->ar->int_status &= ~(1 << ubi32_priv->irq_idx); + + /* + * We only have one stream since we don't mix. Therefore + * we don't need to search through substreams. + */ + if (ubi32_priv->is_capture) { + substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + } else { + substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + } + + if (!substream->runtime) { + snd_printk(KERN_WARNING "No runtime data\n"); + return IRQ_NONE; + } + + ubi32_rd = substream->runtime->private_data; + +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "Ubi32 ALSA interrupt\n"); +#endif + + if (ubi32_rd == NULL) { + snd_printk(KERN_WARNING "No private data\n"); + return IRQ_NONE; + } + + // Check interrupt cause + if (0) { + // Handle the underflow case + } else if ((adr->status & AUDIO_STATUS_PLAY_DMA0_REQUEST) || + (adr->status & AUDIO_STATUS_PLAY_DMA1_REQUEST)) { + if (adr->status & AUDIO_STATUS_PLAY_DMA0_REQUEST) { + dma_to_fill = 0; + adr->status &= ~AUDIO_STATUS_PLAY_DMA0_REQUEST; + } else if (adr->status & AUDIO_STATUS_PLAY_DMA1_REQUEST) { + dma_to_fill = 1; + adr->status &= ~AUDIO_STATUS_PLAY_DMA1_REQUEST; + } + ubi32_rd->period_ptr += ubi32_rd->period_size; + if (ubi32_rd->period_ptr >= ubi32_rd->dma_buffer_end) { + ubi32_rd->period_ptr = ubi32_rd->dma_buffer; + } + adr->dma_xfer_requests[dma_to_fill].ptr = (void *)ubi32_rd->period_ptr; + adr->dma_xfer_requests[dma_to_fill].ctr = ubi32_rd->period_size; + adr->dma_xfer_requests[dma_to_fill].active = 1; +#ifdef CONFIG_SND_DEBUG + snd_printk(KERN_INFO "xfer_request %d ptr=0x%x ctr=%u\n", dma_to_fill, ubi32_rd->period_ptr, ubi32_rd->period_size); +#endif + adr->int_flags |= AUDIO_INT_FLAG_MORE_SAMPLES; + snd_ubi32_vp_int_set(substream->pcm); + } + // If we are interrupted by the VP, that means we completed + // processing one period of audio. We need to inform the upper + // layers of ALSA of this. + snd_pcm_period_elapsed(substream); + + return IRQ_HANDLED; +} + +void __devexit snd_ubi32_pcm_remove(struct ubi32_snd_priv *ubi32_priv) +{ + struct snd_pcm *pcm = ubi32_priv->pcm; + free_irq(ubi32_priv->rx_irq, pcm); +} + +#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 +#error "Change this table to match pcm.h" +#endif +static unsigned int rates[] __initdata = {5512, 8000, 11025, 16000, 22050, + 32000, 44100, 48000, 64000, 88200, + 96000, 176400, 192000}; + +/* + * snd_ubi32_pcm_probe + */ +int __devinit snd_ubi32_pcm_probe(struct ubi32_snd_priv *ubi32_priv, struct platform_device *pdev) +{ + struct snd_pcm *pcm; + int ret, err; + int i; + int j; + int nrates; + unsigned int rate_max = 0; + unsigned int rate_min = 0xFFFFFFFF; + unsigned int rate_mask = 0; + struct audio_dev_regs *adr; + struct resource *res_adr; + struct resource *res_irq_tx; + struct resource *res_irq_rx; + struct ubi32pcm_platform_data *pdata; + + pdata = pdev->dev.platform_data; + if (!pdata) { + return -ENODEV; + } + + /* + * Get our resources, adr is the hardware driver base address + * and the tx and rx irqs are used to communicate with the + * hardware driver. + */ + res_adr = platform_get_resource(pdev, IORESOURCE_MEM, AUDIO_MEM_RESOURCE); + res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, AUDIO_TX_IRQ_RESOURCE); + res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, AUDIO_RX_IRQ_RESOURCE); + if (!res_adr || !res_irq_tx || !res_irq_rx) { + snd_printk(KERN_WARNING "Could not get resources"); + return -ENODEV; + } + + ubi32_priv->ar = (struct audio_regs *)res_adr->start; + ubi32_priv->tx_irq = res_irq_tx->start; + ubi32_priv->rx_irq = res_irq_rx->start; + ubi32_priv->irq_idx = pdata->inst_num; + ubi32_priv->adr = &(ubi32_priv->ar->adr[pdata->inst_num]); + + /* + * Check the version + */ + adr = ubi32_priv->adr; + if (adr->version != AUDIO_DEV_REGS_VERSION) { + snd_printk(KERN_WARNING "This audio_dev_reg is not compatible with this driver\n"); + return -ENODEV; + } + + /* + * Find out the standard rates, also find max and min rates + */ + for (i = 0; i < ARRAY_SIZE(rates); i++) { + int found = 0; + for (j = 0; j < adr->n_sample_rates; j++) { + if (rates[i] == adr->sample_rates[j]) { + /* + * Check to see if it is supported by the dac + */ + if ((rates[i] >= ubi32_priv->min_sample_rate) && + (!ubi32_priv->max_sample_rate || + (ubi32_priv->max_sample_rate && (rates[i] <= ubi32_priv->max_sample_rate)))) { + found = 1; + rate_mask |= (1 << i); + nrates++; + if (rates[i] < rate_min) { + rate_min = rates[i]; + } + if (rates[i] > rate_max) { + rate_max = rates[i]; + } + break; + } + } + } + if (!found) { + rate_mask |= SNDRV_PCM_RATE_KNOT; + } + } + + snd_ubi32_pcm_hw.rates = rate_mask; + snd_ubi32_pcm_hw.rate_min = rate_min; + snd_ubi32_pcm_hw.rate_max = rate_max; + ubi32_pcm_rates.count = adr->n_sample_rates; + ubi32_pcm_rates.list = (unsigned int *)adr->sample_rates; + ubi32_pcm_rates.mask = 0; + + for (i = 0; i < 32; i++) { + if (adr->channel_mask & (1 << i)) { + if (!snd_ubi32_pcm_hw.channels_min) { + snd_ubi32_pcm_hw.channels_min = i; + } + snd_ubi32_pcm_hw.channels_max = i; + } + } + snd_printk(KERN_INFO "Ubi32PCM: channels_min:%u channels_max:%u\n", + snd_ubi32_pcm_hw.channels_min, + snd_ubi32_pcm_hw.channels_max); + + if (adr->caps & AUDIONODE_CAP_BE) { + snd_ubi32_pcm_hw.formats |= SNDRV_PCM_FMTBIT_S16_BE; + } + if (adr->caps & AUDIONODE_CAP_LE) { + snd_ubi32_pcm_hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; + } + + snd_printk(KERN_INFO "Ubi32PCM: rates:%08x min:%u max:%u count:%d fmts:%016llx (%s)\n", + snd_ubi32_pcm_hw.rates, + snd_ubi32_pcm_hw.rate_min, + snd_ubi32_pcm_hw.rate_max, + ubi32_pcm_rates.count, + snd_ubi32_pcm_hw.formats, + ubi32_priv->is_capture ? "capture" : "playback"); + + if (ubi32_priv->is_capture) { + ret = snd_pcm_new(ubi32_priv->card, "Ubi32 PCM", 0, 0, 1, &pcm); + } else { + ret = snd_pcm_new(ubi32_priv->card, "Ubi32 PCM", 0, 1, 0, &pcm); + } + + if (ret < 0) { + return ret; + } + + pcm->private_data = ubi32_priv; + ubi32_priv->pcm = pcm; + ubi32_priv->pdata = pdata; + + pcm->info_flags = 0; + + strcpy(pcm->name, "Ubi32-PCM"); + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 45*1024, 64*1024); + + if (ubi32_priv->is_capture) { + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ubi32_pcm_ops); + } else { + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ubi32_pcm_ops); + } + + /* + * Start up the audio device + */ + adr->int_flags |= AUDIO_INT_FLAG_COMMAND; + adr->command = AUDIO_CMD_ENABLE; + snd_ubi32_vp_int_set(pcm); + + /* + * Request IRQ + */ + err = request_irq(ubi32_priv->rx_irq, snd_ubi32_pcm_interrupt, IRQF_SHARED | IRQF_DISABLED, pcm->name, pcm); + if (err) { + snd_printk(KERN_WARNING "request_irq failed: irq=%d err=%d\n", ubi32_priv->rx_irq, err); + return -ENODEV; + } + + return ret; + +} diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32.h b/target/linux/ubicom32/files/sound/ubicom32/ubi32.h new file mode 100644 index 000000000..f43a2150b --- /dev/null +++ b/target/linux/ubicom32/files/sound/ubicom32/ubi32.h @@ -0,0 +1,102 @@ +/* + * sound/ubicom32/ubi32.h + * Common header file for all ubi32- sound drivers + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see . + */ + +#ifndef _UBI32_H +#define _UBI32_H + +#define SND_UBI32_DEBUG 0 // Debug flag + +#include +#include +#include +#include + +struct ubi32_snd_priv; + +typedef int (*set_channels_t)(struct ubi32_snd_priv *priv, int channels); +typedef int (*set_rate_t)(struct ubi32_snd_priv *priv, int rate); + +struct ubi32_snd_priv { + /* + * Any variables that are needed locally here but NOT in + * the VP itself should go in here. + */ + struct snd_card *card; + struct snd_pcm *pcm; + + /* + * capture (1) or playback (0) + */ + int is_capture; + /* + * DAC parameters. These are the parameters for the specific + * DAC we are driving. The I2S component can run at a range + * of frequencies, but the DAC may be limited. We may want + * to make this an array of some sort in the future? + * + * min/max_sample_rate if set to 0 are ignored. + */ + int max_sample_rate; + int min_sample_rate; + + /* + * The size a period (group) of audio samples. The VP does + * not need to know this; each DMA transfer is made to be + * one period. + */ + u32_t period_size; + + spinlock_t ubi32_lock; + + struct audio_regs *ar; + struct audio_dev_regs *adr; + u32 irq_idx; + u8 tx_irq; + u8 rx_irq; + + void *client; + + /* + * Operations which the base DAC driver can implement + */ + set_channels_t set_channels; + set_rate_t set_rate; + + /* + * platform data + */ + struct ubi32pcm_platform_data *pdata; + + /* + * Private driver data (used for DAC driver control, etc) + */ + void *drvdata; +}; + +#define snd_ubi32_priv_get_drv(priv) ((priv)->drvdata) +#define snd_ubi32_priv_set_drv(priv, data) (((priv)->drvdata) = (void *)(data)) + +extern int snd_ubi32_pcm_probe(struct ubi32_snd_priv *ubi32_priv, struct platform_device *pdev); +extern void snd_ubi32_pcm_remove(struct ubi32_snd_priv *ubi32_priv); + +#endif diff --git a/target/linux/ubicom32/patches-2.6.30/100-ubicom32_support.patch b/target/linux/ubicom32/patches-2.6.30/100-ubicom32_support.patch index 2e0f1a763..eca2740a8 100644 --- a/target/linux/ubicom32/patches-2.6.30/100-ubicom32_support.patch +++ b/target/linux/ubicom32/patches-2.6.30/100-ubicom32_support.patch @@ -1,41663 +1,6 @@ -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/aes_ubicom32.c linux-2.6.30.10-ubi/arch/ubicom32/crypto/aes_ubicom32.c ---- linux-2.6.30.10/arch/ubicom32/crypto/aes_ubicom32.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/aes_ubicom32.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,458 @@ -+/* -+ * arch/ubicom32/crypto/aes_ubicom32.c -+ * Ubicom32 implementation of the AES Cipher Algorithm. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crypto_ubicom32.h" -+#include -+ -+struct ubicom32_aes_ctx { -+ u8 key[AES_MAX_KEY_SIZE]; -+ u32 ctrl; -+ int key_len; -+}; -+ -+static inline void aes_hw_set_key(const u8 *key, u8 key_len) -+{ -+ /* -+ * switch case has more overhead than 4 move.4 instructions, so just copy 256 bits -+ */ -+ SEC_SET_KEY_256(key); -+} -+ -+static inline void aes_hw_set_iv(const u8 *iv) -+{ -+ SEC_SET_IV_4W(iv); -+} -+ -+static inline void aes_hw_cipher(u8 *out, const u8 *in) -+{ -+ SEC_SET_INPUT_4W(in); -+ -+ asm volatile ( -+ " ; start AES by writing 0x40(SECURITY_BASE) \n\t" -+ " move.4 0x40(%0), #0x01 \n\t" -+ " pipe_flush 0 \n\t" -+ " \n\t" -+ " ; wait for the module to calculate the output \n\t" -+ " btst 0x04(%0), #0 \n\t" -+ " jmpne.f .-4 \n\t" -+ : -+ : "a" (SEC_BASE) -+ : "cc" -+ ); -+ -+ SEC_GET_OUTPUT_4W(out); -+} -+ -+static int __ocm_text aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, -+ unsigned int key_len) -+{ -+ struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm); -+ -+ uctx->key_len = key_len; -+ memcpy(uctx->key, in_key, key_len); -+ -+ /* -+ * leave out HASH_ALG (none = 0), CBC (no = 0), DIR (unknown) yet -+ */ -+ switch (uctx->key_len) { -+ case 16: -+ uctx->ctrl = SEC_KEY_128_BITS | SEC_ALG_AES; -+ break; -+ case 24: -+ uctx->ctrl = SEC_KEY_192_BITS | SEC_ALG_AES; -+ break; -+ case 32: -+ uctx->ctrl = SEC_KEY_256_BITS | SEC_ALG_AES; -+ break; -+ } -+ -+ return 0; -+} -+ -+static inline void aes_cipher(struct crypto_tfm *tfm, u8 *out, const u8 *in, u32 extra_flags) -+{ -+ const struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm); -+ -+ hw_crypto_lock(); -+ hw_crypto_check(); -+ hw_crypto_set_ctrl(uctx->ctrl | extra_flags); -+ -+ aes_hw_set_key(uctx->key, uctx->key_len); -+ aes_hw_cipher(out, in); -+ -+ hw_crypto_unlock(); -+} -+ -+static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -+{ -+ aes_cipher(tfm, out, in, SEC_DIR_ENCRYPT); -+} -+ -+static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -+{ -+ aes_cipher(tfm, out, in, SEC_DIR_DECRYPT); -+} -+ -+static struct crypto_alg aes_alg = { -+ .cra_name = "aes", -+ .cra_driver_name = "aes-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, -+ .cra_blocksize = AES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_aes_ctx), -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), -+ .cra_u = { -+ .cipher = { -+ .cia_min_keysize = AES_MIN_KEY_SIZE, -+ .cia_max_keysize = AES_MAX_KEY_SIZE, -+ .cia_setkey = aes_set_key, -+ .cia_encrypt = aes_encrypt, -+ .cia_decrypt = aes_decrypt, -+ } -+ } -+}; -+ -+static void __ocm_text ecb_aes_crypt_loop(u8 *out, u8 *in, unsigned int n) -+{ -+ while (likely(n)) { -+ aes_hw_cipher(out, in); -+ out += AES_BLOCK_SIZE; -+ in += AES_BLOCK_SIZE; -+ n -= AES_BLOCK_SIZE; -+ } -+} -+ -+static int __ocm_text ecb_aes_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, -+ struct scatterlist *src, unsigned int nbytes, u32 extra_flags) -+{ -+ const struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm); -+ int ret; -+ -+ struct blkcipher_walk walk; -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ ret = blkcipher_walk_virt(desc, &walk); -+ if (ret) { -+ return ret; -+ } -+ -+ hw_crypto_lock(); -+ hw_crypto_check(); -+ -+ hw_crypto_set_ctrl(uctx->ctrl | extra_flags); -+ aes_hw_set_key(uctx->key, uctx->key_len); -+ -+ while (likely((nbytes = walk.nbytes))) { -+ /* only use complete blocks */ -+ unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1); -+ u8 *out = walk.dst.virt.addr; -+ u8 *in = walk.src.virt.addr; -+ -+ /* finish n/16 blocks */ -+ ecb_aes_crypt_loop(out, in, n); -+ -+ nbytes &= AES_BLOCK_SIZE - 1; -+ ret = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ hw_crypto_unlock(); -+ return ret; -+} -+ -+static int ecb_aes_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT); -+} -+ -+static int ecb_aes_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT); -+} -+ -+static struct crypto_alg ecb_aes_alg = { -+ .cra_name = "ecb(aes)", -+ .cra_driver_name = "ecb-aes-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = AES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_aes_ctx), -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = AES_MIN_KEY_SIZE, -+ .max_keysize = AES_MAX_KEY_SIZE, -+ .setkey = aes_set_key, -+ .encrypt = ecb_aes_encrypt, -+ .decrypt = ecb_aes_decrypt, -+ } -+ } -+}; -+ -+#if CRYPTO_UBICOM32_LOOP_ASM -+void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ asm volatile ( -+ "; set init. iv 4w \n\t" -+ " move.4 0x50(%0), 0x0(%3) \n\t" -+ " move.4 0x54(%0), 0x4(%3) \n\t" -+ " move.4 0x58(%0), 0x8(%3) \n\t" -+ " move.4 0x5c(%0), 0xc(%3) \n\t" -+ " \n\t" -+ "; we know n > 0, so we can always \n\t" -+ "; load the first block \n\t" -+ "; set input 4w \n\t" -+ " move.4 0x30(%0), 0x0(%2) \n\t" -+ " move.4 0x34(%0), 0x4(%2) \n\t" -+ " move.4 0x38(%0), 0x8(%2) \n\t" -+ " move.4 0x3c(%0), 0xc(%2) \n\t" -+ " \n\t" -+ "; kickoff hw \n\t" -+ " move.4 0x40(%0), %2 \n\t" -+ " \n\t" -+ "; update n & flush \n\t" -+ " add.4 %4, #-16, %4 \n\t" -+ " pipe_flush 0 \n\t" -+ " \n\t" -+ "; while (n): work on 2nd block \n\t" -+ " 1: lsl.4 d15, %4, #0x0 \n\t" -+ " jmpeq.f 5f \n\t" -+ " \n\t" -+ "; set input 4w (2nd) \n\t" -+ " move.4 0x30(%0), 0x10(%2) \n\t" -+ " move.4 0x34(%0), 0x14(%2) \n\t" -+ " move.4 0x38(%0), 0x18(%2) \n\t" -+ " move.4 0x3c(%0), 0x1c(%2) \n\t" -+ " \n\t" -+ "; update n/in asap while waiting \n\t" -+ " add.4 %4, #-16, %4 \n\t" -+ " move.4 d15, 16(%2)++ \n\t" -+ " \n\t" -+ "; wait for the previous output \n\t" -+ " btst 0x04(%0), #0 \n\t" -+ " jmpne.f -4 \n\t" -+ " \n\t" -+ "; read previous output \n\t" -+ " move.4 0x0(%1), 0x50(%0) \n\t" -+ " move.4 0x4(%1), 0x54(%0) \n\t" -+ " move.4 0x8(%1), 0x58(%0) \n\t" -+ " move.4 0xc(%1), 0x5c(%0) \n\t" -+ " \n\t" -+ "; kick off hw for 2nd input \n\t" -+ " move.4 0x40(%0), %2 \n\t" -+ " \n\t" -+ "; update out asap \n\t" -+ " move.4 d15, 16(%1)++ \n\t" -+ " \n\t" -+ "; go back to loop \n\t" -+ " jmpt 1b \n\t" -+ " \n\t" -+ "; wait for last output \n\t" -+ " 5: btst 0x04(%0), #0 \n\t" -+ " jmpne.f -4 \n\t" -+ " \n\t" -+ "; read last output \n\t" -+ " move.4 0x0(%1), 0x50(%0) \n\t" -+ " move.4 0x4(%1), 0x54(%0) \n\t" -+ " move.4 0x8(%1), 0x58(%0) \n\t" -+ " move.4 0xc(%1), 0x5c(%0) \n\t" -+ " \n\t" -+ "; copy out iv \n\t" -+ " move.4 0x0(%3), 0x50(%0) \n\t" -+ " move.4 0x4(%3), 0x54(%0) \n\t" -+ " move.4 0x8(%3), 0x58(%0) \n\t" -+ " move.4 0xc(%3), 0x5c(%0) \n\t" -+ " \n\t" -+ : -+ : "a" (SEC_BASE), "a" (out), "a" (in), "a" (iv), "d" (n) -+ : "d15", "cc" -+ ); -+} -+ -+#else -+ -+static void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ aes_hw_set_iv(iv); -+ while (likely(n)) { -+ aes_hw_cipher(out, in); -+ out += AES_BLOCK_SIZE; -+ in += AES_BLOCK_SIZE; -+ n -= AES_BLOCK_SIZE; -+ } -+ SEC_COPY_4W(iv, out - AES_BLOCK_SIZE); -+} -+ -+#endif -+ -+static void __ocm_text cbc_aes_decrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ while (likely(n)) { -+ aes_hw_set_iv(iv); -+ SEC_COPY_4W(iv, in); -+ aes_hw_cipher(out, in); -+ out += AES_BLOCK_SIZE; -+ in += AES_BLOCK_SIZE; -+ n -= AES_BLOCK_SIZE; -+ } -+} -+ -+static int __ocm_text cbc_aes_crypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes, u32 extra_flags) -+{ -+ struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm); -+ int ret; -+ -+ struct blkcipher_walk walk; -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ ret = blkcipher_walk_virt(desc, &walk); -+ if (unlikely(ret)) { -+ return ret; -+ } -+ -+ hw_crypto_lock(); -+ hw_crypto_check(); -+ -+ hw_crypto_set_ctrl(uctx->ctrl | extra_flags); -+ aes_hw_set_key(uctx->key, uctx->key_len); -+ -+ while (likely((nbytes = walk.nbytes))) { -+ /* only use complete blocks */ -+ unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1); -+ if (likely(n)) { -+ u8 *out = walk.dst.virt.addr; -+ u8 *in = walk.src.virt.addr; -+ -+ if (extra_flags & SEC_DIR_ENCRYPT) { -+ cbc_aes_encrypt_loop(out, in, walk.iv, n); -+ } else { -+ cbc_aes_decrypt_loop(out, in, walk.iv, n); -+ } -+ } -+ -+ nbytes &= AES_BLOCK_SIZE - 1; -+ ret = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ hw_crypto_unlock(); -+ -+ return ret; -+} -+ -+static int __ocm_text cbc_aes_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT | SEC_CBC_SET); -+} -+ -+static int __ocm_text cbc_aes_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT | SEC_CBC_SET); -+} -+ -+static struct crypto_alg cbc_aes_alg = { -+ .cra_name = "cbc(aes)", -+ .cra_driver_name = "cbc-aes-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = AES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_aes_ctx), -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = AES_MIN_KEY_SIZE, -+ .max_keysize = AES_MAX_KEY_SIZE, -+ .ivsize = AES_BLOCK_SIZE, -+ .setkey = aes_set_key, -+ .encrypt = cbc_aes_encrypt, -+ .decrypt = cbc_aes_decrypt, -+ } -+ } -+}; -+ -+static int __init aes_init(void) -+{ -+ int ret; -+ -+ hw_crypto_init(); -+ -+ ret = crypto_register_alg(&aes_alg); -+ if (ret) -+ goto aes_err; -+ -+ ret = crypto_register_alg(&ecb_aes_alg); -+ if (ret) -+ goto ecb_aes_err; -+ -+ ret = crypto_register_alg(&cbc_aes_alg); -+ if (ret) -+ goto cbc_aes_err; -+ -+out: -+ return ret; -+ -+cbc_aes_err: -+ crypto_unregister_alg(&ecb_aes_alg); -+ecb_aes_err: -+ crypto_unregister_alg(&aes_alg); -+aes_err: -+ goto out; -+} -+ -+static void __exit aes_fini(void) -+{ -+ crypto_unregister_alg(&cbc_aes_alg); -+ crypto_unregister_alg(&ecb_aes_alg); -+ crypto_unregister_alg(&aes_alg); -+} -+ -+module_init(aes_init); -+module_exit(aes_fini); -+ -+MODULE_ALIAS("aes"); -+ -+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/crypto_des.h linux-2.6.30.10-ubi/arch/ubicom32/crypto/crypto_des.h ---- linux-2.6.30.10/arch/ubicom32/crypto/crypto_des.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/crypto_des.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,34 @@ -+/* -+ * arch/ubicom32/crypto/crypto_des.h -+ * Function for checking keys for the DES and Triple DES Encryption -+ * algorithms. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef __CRYPTO_DES_H__ -+#define __CRYPTO_DES_H__ -+ -+extern int crypto_des_check_key(const u8*, unsigned int, u32*); -+ -+#endif /* __CRYPTO_DES_H__ */ -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/crypto_ubicom32.c linux-2.6.30.10-ubi/arch/ubicom32/crypto/crypto_ubicom32.c ---- linux-2.6.30.10/arch/ubicom32/crypto/crypto_ubicom32.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/crypto_ubicom32.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,50 @@ -+/* -+ * arch/ubicom32/crypto/crypto_ubicom32.c -+ * Generic code to support ubicom32 hardware crypto accelerator -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include "crypto_ubicom32.h" -+ -+spinlock_t crypto_ubicom32_lock; -+bool crypto_ubicom32_inited = false; -+volatile bool crypto_ubicom32_on = false; -+volatile unsigned long crypto_ubicom32_last_use; -+ -+struct timer_list crypto_ubicom32_ps_timer; -+void crypto_ubicom32_ps_check(unsigned long data) -+{ -+ unsigned long idle_time = msecs_to_jiffies(HW_CRYPTO_PS_MAX_IDLE_MS); -+ -+ BUG_ON(!crypto_ubicom32_on); -+ -+ if (((jiffies - crypto_ubicom32_last_use) > idle_time) && spin_trylock_bh(&crypto_ubicom32_lock)) { -+ hw_crypto_turn_off(); -+ spin_unlock_bh(&crypto_ubicom32_lock); -+ return; -+ } -+ -+ /* keep monitoring */ -+ hw_crypto_ps_start(); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/crypto_ubicom32.h linux-2.6.30.10-ubi/arch/ubicom32/crypto/crypto_ubicom32.h ---- linux-2.6.30.10/arch/ubicom32/crypto/crypto_ubicom32.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/crypto_ubicom32.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,346 @@ -+/* -+ * arch/ubicom32/crypto/crypto_ubicom32.h -+ * Support for Ubicom32 cryptographic instructions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _CRYPTO_ARCH_UBICOM32_CRYPT_H -+#define _CRYPTO_ARCH_UBICOM32_CRYPT_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define CRYPTO_UBICOM32_LOOP_ASM 1 -+#define CRYPTO_UBICOM32_ALIGNMENT 4 -+#define SEC_ALIGNED(p) (((u32)p & 3) == 0) -+ -+#define SEC_BASE SECURITY_BASE -+#define SEC_KEY_OFFSET SECURITY_KEY_VALUE(0) -+#define SEC_INPUT_OFFSET SECURITY_KEY_IN(0) -+#define SEC_OUTPUT_OFFSET SECURITY_KEY_OUT(0) -+#define SEC_HASH_OFFSET SECURITY_KEY_HASH(0) -+ -+#define SEC_KEY_128_BITS SECURITY_CTRL_KEY_SIZE(0) -+#define SEC_KEY_192_BITS SECURITY_CTRL_KEY_SIZE(1) -+#define SEC_KEY_256_BITS SECURITY_CTRL_KEY_SIZE(2) -+ -+#define SEC_HASH_NONE SECURITY_CTRL_HASH_ALG_NONE -+#define SEC_HASH_MD5 SECURITY_CTRL_HASH_ALG_MD5 -+#define SEC_HASH_SHA1 SECURITY_CTRL_HASH_ALG_SHA1 -+ -+#define SEC_CBC_SET SECURITY_CTRL_CBC -+#define SEC_CBC_NONE 0 -+ -+#define SEC_ALG_AES SECURITY_CTRL_CIPHER_ALG_AES -+#define SEC_ALG_NONE SECURITY_CTRL_CIPHER_ALG_NONE -+#define SEC_ALG_DES SECURITY_CTRL_CIPHER_ALG_DES -+#define SEC_ALG_3DES SECURITY_CTRL_CIPHER_ALG_3DES -+ -+#define SEC_DIR_ENCRYPT SECURITY_CTRL_ENCIPHER -+#define SEC_DIR_DECRYPT 0 -+ -+#define CRYPTO_UBICOM32_PRIORITY 300 -+#define CRYPTO_UBICOM32_COMPOSITE_PRIORITY 400 -+ -+#define HW_CRYPTO_PS_MAX_IDLE_MS 100 /* idle time (ms) before shuting down sm */ -+ -+extern spinlock_t crypto_ubicom32_lock; -+extern bool crypto_ubicom32_inited; -+extern volatile bool crypto_ubicom32_on; -+extern volatile unsigned long crypto_ubicom32_last_use; -+extern struct timer_list crypto_ubicom32_ps_timer; -+extern void crypto_ubicom32_ps_check(unsigned long data); -+ -+#define SEC_COPY_2W(t, s) \ -+ asm volatile ( \ -+ " move.4 0(%0), 0(%1) \n\t" \ -+ " move.4 4(%0), 4(%1) \n\t" \ -+ \ -+ : \ -+ : "a" (t), "a" (s) \ -+ ) -+ -+#define SEC_COPY_4W(t, s) \ -+ asm volatile ( \ -+ " move.4 0(%0), 0(%1) \n\t" \ -+ " move.4 4(%0), 4(%1) \n\t" \ -+ " move.4 8(%0), 8(%1) \n\t" \ -+ " move.4 12(%0), 12(%1) \n\t" \ -+ : \ -+ : "a" (t), "a" (s) \ -+ ) -+ -+#define SEC_COPY_5W(t, s) \ -+ asm volatile ( \ -+ " move.4 0(%0), 0(%1) \n\t" \ -+ " move.4 4(%0), 4(%1) \n\t" \ -+ " move.4 8(%0), 8(%1) \n\t" \ -+ " move.4 12(%0), 12(%1) \n\t" \ -+ " move.4 16(%0), 16(%1) \n\t" \ -+ : \ -+ : "a" (t), "a" (s) \ -+ ) -+ -+#define SEC_SET_KEY_2W(x) \ -+ asm volatile ( \ -+ " ; write key to Security Keyblock \n\t" \ -+ " move.4 0x10(%0), 0(%1) \n\t" \ -+ " move.4 0x14(%0), 4(%1) \n\t" \ -+ : \ -+ : "a" (SECURITY_BASE), "a" (x) \ -+ ) -+ -+#define SEC_SET_KEY_4W(x) \ -+ asm volatile ( \ -+ " ; write key to Security Keyblock \n\t" \ -+ " move.4 0x10(%0), 0(%1) \n\t" \ -+ " move.4 0x14(%0), 4(%1) \n\t" \ -+ " move.4 0x18(%0), 8(%1) \n\t" \ -+ " move.4 0x1c(%0), 12(%1) \n\t" \ -+ : \ -+ : "a"(SECURITY_BASE), "a"(x) \ -+ ) -+ -+#define SEC_SET_KEY_6W(x) \ -+ asm volatile ( \ -+ " ; write key to Security Keyblock \n\t" \ -+ " move.4 0x10(%0), 0(%1) \n\t" \ -+ " move.4 0x14(%0), 4(%1) \n\t" \ -+ " move.4 0x18(%0), 8(%1) \n\t" \ -+ " move.4 0x1c(%0), 12(%1) \n\t" \ -+ " move.4 0x20(%0), 16(%1) \n\t" \ -+ " move.4 0x24(%0), 20(%1) \n\t" \ -+ : \ -+ : "a" (SECURITY_BASE), "a" (x) \ -+ ) -+ -+#define SEC_SET_KEY_8W(x) \ -+ asm volatile ( \ -+ " ; write key to Security Keyblock \n\t" \ -+ " move.4 0x10(%0), 0(%1) \n\t" \ -+ " move.4 0x14(%0), 4(%1) \n\t" \ -+ " move.4 0x18(%0), 8(%1) \n\t" \ -+ " move.4 0x1c(%0), 12(%1) \n\t" \ -+ " move.4 0x20(%0), 16(%1) \n\t" \ -+ " move.4 0x24(%0), 20(%1) \n\t" \ -+ " move.4 0x28(%0), 24(%1) \n\t" \ -+ " move.4 0x2c(%0), 28(%1) \n\t" \ -+ : \ -+ : "a" (SECURITY_BASE), "a" (x) \ -+ ) -+ -+#define SEC_SET_KEY_64(k) SEC_SET_KEY_2W(k) -+#define SEC_SET_KEY_128(k) SEC_SET_KEY_4W(k) -+#define SEC_SET_KEY_192(k) SEC_SET_KEY_6W(k) -+#define SEC_SET_KEY_256(k) SEC_SET_KEY_8W(k) -+ -+#define DES_SET_KEY(x) SEC_SET_KEY_64(x) -+#define DES3_SET_KEY(x) SEC_SET_KEY_192(x) -+ -+#define SEC_SET_INPUT_2W(x) \ -+ asm volatile ( \ -+ " ; write key to Security Keyblock \n\t" \ -+ " move.4 0x30(%0), 0(%1) \n\t" \ -+ " move.4 0x34(%0), 4(%1) \n\t" \ -+ : \ -+ : "a" (SECURITY_BASE), "a" (x) \ -+ ) -+ -+#define SEC_GET_OUTPUT_2W(x) \ -+ asm volatile ( \ -+ " ; write key to Security Keyblock \n\t" \ -+ " move.4 0(%1), 0x50(%0) \n\t" \ -+ " move.4 4(%1), 0x54(%0) \n\t" \ -+ : \ -+ : "a" (SECURITY_BASE), "a" (x) \ -+ ) -+ -+#define SEC_SET_INPUT_4W(x) \ -+ asm volatile ( \ -+ " ; write key to Security Keyblock \n\t" \ -+ " move.4 0x30(%0), 0(%1) \n\t" \ -+ " move.4 0x34(%0), 4(%1) \n\t" \ -+ " move.4 0x38(%0), 8(%1) \n\t" \ -+ " move.4 0x3c(%0), 12(%1) \n\t" \ -+ : \ -+ : "a" (SECURITY_BASE), "a" (x) \ -+ ) -+ -+#define SEC_GET_OUTPUT_4W(x) \ -+ asm volatile ( \ -+ " ; read output from Security Keyblock \n\t" \ -+ " move.4 0(%1), 0x50(%0) \n\t" \ -+ " move.4 4(%1), 0x54(%0) \n\t" \ -+ " move.4 8(%1), 0x58(%0) \n\t" \ -+ " move.4 12(%1), 0x5c(%0) \n\t" \ -+ : \ -+ : "a" (SECURITY_BASE), "a" (x) \ -+ ) -+ -+#define SEC_SET_IV_4W(x) \ -+ asm volatile ( \ -+ " ; write IV to Security Keyblock \n\t" \ -+ " move.4 0x50(%0), 0(%1) \n\t" \ -+ " move.4 0x54(%0), 4(%1) \n\t" \ -+ " move.4 0x58(%0), 8(%1) \n\t" \ -+ " move.4 0x5c(%0), 12(%1) \n\t" \ -+ : \ -+ : "a" (SECURITY_BASE), "a" (x) \ -+ ) -+ -+#define SEC_PIPE_FLUSH() asm volatile ( " pipe_flush 0 \n\t" ) -+ -+static inline void hw_crypto_set_ctrl(uint32_t c) -+{ -+ asm volatile ( -+ " move.4 0(%0), %1 \n\t" -+ : -+ : "a" (SECURITY_BASE + SECURITY_CTRL), "d" (c) -+ ); -+} -+ -+static inline void hw_crypto_ps_start(void) -+{ -+ crypto_ubicom32_ps_timer.expires = jiffies + msecs_to_jiffies(HW_CRYPTO_PS_MAX_IDLE_MS >> 1); -+ add_timer(&crypto_ubicom32_ps_timer); -+} -+ -+static inline void hw_crypto_turn_on(void) -+{ -+ asm volatile ( -+ " moveai A4, %0 \n\t" -+ " bset 0x0(A4), 0x0(A4), %1 \n\t" -+ " cycles 11 \n\t" -+ : -+ : "i" (OCP_BASE >> 7), "i" (GEN_CLK_PLL_SECURITY_BIT_NO) -+ : "a4", "cc" -+ ); -+ crypto_ubicom32_on = true; -+} -+ -+static inline void hw_crypto_turn_off(void) -+{ -+ asm volatile ( -+ " moveai A4, %0 \n\t" -+ " bclr 0x0(A4), 0x0(A4), %1 \n\t" -+ : -+ : "i" (OCP_BASE >> 7), "i" (GEN_CLK_PLL_SECURITY_BIT_NO) -+ : "a4", "cc" -+ ); -+ crypto_ubicom32_on = false; -+} -+ -+/* -+ * hw_crypto_check -+ * Most probably hw crypto is called in clusters and it makes no sense to turn it off -+ * and on and waster 13 cycles every time. -+ */ -+static inline void hw_crypto_check(void) -+{ -+ if (likely(crypto_ubicom32_on)) { -+ return; -+ } -+ crypto_ubicom32_last_use = jiffies; -+ hw_crypto_turn_on(); -+ hw_crypto_ps_start(); -+} -+ -+/* -+ * hw_crypto_ps_init -+ * Init power save timer -+ */ -+static inline void hw_crypto_ps_init(void) -+{ -+ init_timer_deferrable(&crypto_ubicom32_ps_timer); -+ crypto_ubicom32_ps_timer.function = crypto_ubicom32_ps_check; -+ crypto_ubicom32_ps_timer.data = 0; -+} -+ -+/* -+ * hw_crypto_init() -+ * Initialize OCP security module lock and disables its clock. -+ */ -+static inline void hw_crypto_init(void) -+{ -+ if (!crypto_ubicom32_inited) { -+ crypto_ubicom32_inited = true; -+ spin_lock_init(&crypto_ubicom32_lock); -+ hw_crypto_ps_init(); -+ hw_crypto_turn_off(); -+ } -+} -+ -+/* -+ * hw_crypto_lock() -+ * Locks the OCP security module and enables its clock. -+ */ -+static inline void hw_crypto_lock(void) -+{ -+ spin_lock_bh(&crypto_ubicom32_lock); -+} -+ -+/* -+ * hw_crypto_unlock() -+ * Unlocks the OCP security module and disables its clock. -+ */ -+static inline void hw_crypto_unlock(void) -+{ -+ crypto_ubicom32_last_use = jiffies; -+ spin_unlock_bh(&crypto_ubicom32_lock); -+} -+ -+#define CONFIG_CRYPTO_UBICOM32_DEBUG 1 -+ -+#ifdef CONFIG_CRYPTO_UBICOM32_DEBUG -+static inline void hex_dump(void *buf, int b_size, const char *msg) -+{ -+ u8 *b = (u8 *)buf; -+ int i; -+ if (msg) { -+ printk("%s:\t", msg); -+ } -+ -+ for (i=0; i < b_size; i++) { -+ printk("%02x ", b[i]); -+ if ((i & 3) == 3) { -+ printk(" "); -+ } -+ if ((i & 31) == 31) { -+ printk("\n"); -+ } -+ } -+ printk("\n"); -+} -+#define UBICOM32_SEC_DUMP(a, b, c) hex_dump(a, b, c) -+#else -+#define UBICOM32_SEC_DUMP(a, b, c) -+#endif -+ -+#endif /* _CRYPTO_ARCH_UBICOM32_CRYPT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/des_check_key.c linux-2.6.30.10-ubi/arch/ubicom32/crypto/des_check_key.c ---- linux-2.6.30.10/arch/ubicom32/crypto/des_check_key.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/des_check_key.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,148 @@ -+/* -+ * arch/ubicom32/crypto/des_check_key.c -+ * Ubicom32 architecture function for checking keys for the DES and -+ * Tripple DES Encryption algorithms. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * Originally released as descore by Dana L. How . -+ * Modified by Raimar Falke for the Linux-Kernel. -+ * Derived from Cryptoapi and Nettle implementations, adapted for in-place -+ * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL. -+ * -+ * s390 Version: -+ * Copyright IBM Corp. 2003 -+ * Author(s): Thomas Spatzier -+ * Jan Glauber (jan.glauber@de.ibm.com) -+ * -+ * Derived from "crypto/des.c" -+ * Copyright (c) 1992 Dana L. How. -+ * Copyright (c) Raimar Falke -+ * Copyright (c) Gisle Sflensminde -+ * Copyright (C) 2001 Niels Mvller. -+ * Copyright (c) 2002 James Morris -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include "crypto_des.h" -+ -+#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o)) -+ -+static const u8 parity[] = { -+ 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3, -+ 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, -+ 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, -+ 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, -+ 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, -+ 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, -+ 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, -+ 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8, -+}; -+ -+/* -+ * RFC2451: Weak key checks SHOULD be performed. -+ */ -+int -+crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags) -+{ -+ u32 n, w; -+ -+ n = parity[key[0]]; n <<= 4; -+ n |= parity[key[1]]; n <<= 4; -+ n |= parity[key[2]]; n <<= 4; -+ n |= parity[key[3]]; n <<= 4; -+ n |= parity[key[4]]; n <<= 4; -+ n |= parity[key[5]]; n <<= 4; -+ n |= parity[key[6]]; n <<= 4; -+ n |= parity[key[7]]; -+ w = 0x88888888L; -+ -+ if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY) -+ && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */ -+ if (n < 0x41415151) { -+ if (n < 0x31312121) { -+ if (n < 0x14141515) { -+ /* 01 01 01 01 01 01 01 01 */ -+ if (n == 0x11111111) goto weak; -+ /* 01 1F 01 1F 01 0E 01 0E */ -+ if (n == 0x13131212) goto weak; -+ } else { -+ /* 01 E0 01 E0 01 F1 01 F1 */ -+ if (n == 0x14141515) goto weak; -+ /* 01 FE 01 FE 01 FE 01 FE */ -+ if (n == 0x16161616) goto weak; -+ } -+ } else { -+ if (n < 0x34342525) { -+ /* 1F 01 1F 01 0E 01 0E 01 */ -+ if (n == 0x31312121) goto weak; -+ /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */ -+ if (n == 0x33332222) goto weak; -+ } else { -+ /* 1F E0 1F E0 0E F1 0E F1 */ -+ if (n == 0x34342525) goto weak; -+ /* 1F FE 1F FE 0E FE 0E FE */ -+ if (n == 0x36362626) goto weak; -+ } -+ } -+ } else { -+ if (n < 0x61616161) { -+ if (n < 0x44445555) { -+ /* E0 01 E0 01 F1 01 F1 01 */ -+ if (n == 0x41415151) goto weak; -+ /* E0 1F E0 1F F1 0E F1 0E */ -+ if (n == 0x43435252) goto weak; -+ } else { -+ /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */ -+ if (n == 0x44445555) goto weak; -+ /* E0 FE E0 FE F1 FE F1 FE */ -+ if (n == 0x46465656) goto weak; -+ } -+ } else { -+ if (n < 0x64646565) { -+ /* FE 01 FE 01 FE 01 FE 01 */ -+ if (n == 0x61616161) goto weak; -+ /* FE 1F FE 1F FE 0E FE 0E */ -+ if (n == 0x63636262) goto weak; -+ } else { -+ /* FE E0 FE E0 FE F1 FE F1 */ -+ if (n == 0x64646565) goto weak; -+ /* FE FE FE FE FE FE FE FE */ -+ if (n == 0x66666666) goto weak; -+ } -+ } -+ } -+ } -+ return 0; -+weak: -+ *flags |= CRYPTO_TFM_RES_WEAK_KEY; -+ return -EINVAL; -+} -+ -+EXPORT_SYMBOL(crypto_des_check_key); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Key Check function for DES & DES3 Cipher Algorithms"); -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/des_ubicom32.c linux-2.6.30.10-ubi/arch/ubicom32/crypto/des_ubicom32.c ---- linux-2.6.30.10/arch/ubicom32/crypto/des_ubicom32.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/des_ubicom32.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,761 @@ -+/* -+ * arch/ubicom32/crypto/des_ubicom32.c -+ * Ubicom32 implementation of the DES Cipher Algorithm. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+ -+#include "crypto_ubicom32.h" -+extern int crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags); -+ -+#define DES_BLOCK_SIZE 8 -+#define DES_KEY_SIZE 8 -+ -+#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE) -+#define DES3_192_BLOCK_SIZE DES_BLOCK_SIZE -+ -+#define DES3_SUB_KEY(key, i) (((u8 *)key) + (i * DES_KEY_SIZE)) -+ -+enum des_ops { -+ DES_ENCRYPT, -+ DES_DECRYPT, -+ -+ DES3_EDE_ENCRYPT, -+ DES3_EDE_DECRYPT, -+ -+#ifdef DES3_EEE -+ DES3_EEE_ENCRYPT, -+ DES3_EEE_DECRYPT, -+#endif -+}; -+ -+struct ubicom32_des_ctx { -+ u8 key[3 * DES_KEY_SIZE]; -+ u32 ctrl; -+ int key_len; -+}; -+ -+static inline void des_hw_set_key(const u8 *key, u8 key_len) -+{ -+ /* -+ * HW 3DES is not tested yet, use DES just as ipOS -+ */ -+ DES_SET_KEY(key); -+} -+ -+static inline void des_hw_cipher(u8 *out, const u8 *in) -+{ -+ SEC_SET_INPUT_2W(in); -+ -+ asm volatile ( -+ " ; start DES by writing 0x38(SECURITY_BASE) \n\t" -+ " move.4 0x38(%0), #0x01 \n\t" -+ " pipe_flush 0 \n\t" -+ " \n\t" -+ " ; wait for the module to calculate the output \n\t" -+ " btst 0x04(%0), #0 \n\t" -+ " jmpne.f .-4 \n\t" -+ : -+ : "a" (SEC_BASE) -+ : "cc" -+ ); -+ -+ SEC_GET_OUTPUT_2W(out); -+} -+ -+ -+static void inline des3_hw_ede_encrypt(u8 *keys, u8 *out, const u8 *in) -+{ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 0), DES_KEY_SIZE); -+ des_hw_cipher(out, in); -+ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 1), DES_KEY_SIZE); -+ des_hw_cipher(out, out); -+ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 2), DES_KEY_SIZE); -+ des_hw_cipher(out, out); -+} -+ -+static void inline des3_hw_ede_decrypt(u8 *keys, u8 *out, const u8 *in) -+{ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 2), DES_KEY_SIZE); -+ des_hw_cipher(out, in); -+ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 1), DES_KEY_SIZE); -+ des_hw_cipher(out, out); -+ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 0), DES_KEY_SIZE); -+ des_hw_cipher(out, out); -+} -+ -+#ifdef DES3_EEE -+static void inline des3_hw_eee_encrypt(u8 *keys, u8 *out, const u8 *in) -+{ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 0), 2); -+ des_hw_cipher(out, in); -+ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 1), 2); -+ des_hw_cipher(out, out); -+ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 2), 2); -+ des_hw_cipher(out, out); -+} -+ -+static void inline des3_hw_eee_decrypt(u8 *keys, u8 *out, const u8 *in) -+{ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 2), 2); -+ des_hw_cipher(out, in); -+ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 1), 2); -+ des_hw_cipher(out, out); -+ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); -+ des_hw_set_key(DES3_SUB_KEY(keys, 0), 2); -+ des_hw_cipher(out, out); -+} -+#endif -+ -+static int des_setkey(struct crypto_tfm *tfm, const u8 *key, -+ unsigned int keylen) -+{ -+ struct ubicom32_des_ctx *dctx = crypto_tfm_ctx(tfm); -+ u32 *flags = &tfm->crt_flags; -+ int ret; -+ -+ /* test if key is valid (not a weak key) */ -+ ret = crypto_des_check_key(key, keylen, flags); -+ if (ret == 0) { -+ memcpy(dctx->key, key, keylen); -+ dctx->key_len = keylen; -+ //dctx->ctrl = (keylen == DES_KEY_SIZE) ? SEC_ALG_DES : SEC_ALG_3DES -+ /* 2DES and 3DES are both implemented with DES hw function */ -+ dctx->ctrl = SEC_ALG_DES; -+ } -+ return ret; -+} -+ -+static inline void des_cipher_1b(struct crypto_tfm *tfm, u8 *out, const u8 *in, u32 extra_flags) -+{ -+ const struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm); -+ -+ hw_crypto_lock(); -+ hw_crypto_check(); -+ hw_crypto_set_ctrl(uctx->ctrl | extra_flags); -+ -+ des_hw_set_key(uctx->key, uctx->key_len); -+ des_hw_cipher(out, in); -+ -+ hw_crypto_unlock(); -+} -+ -+static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -+{ -+ des_cipher_1b(tfm, out, in, SEC_DIR_ENCRYPT); -+} -+ -+static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -+{ -+ des_cipher_1b(tfm, out, in, SEC_DIR_DECRYPT); -+} -+ -+static struct crypto_alg des_alg = { -+ .cra_name = "des", -+ .cra_driver_name = "des-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, -+ .cra_blocksize = DES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_des_ctx), -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(des_alg.cra_list), -+ .cra_u = { -+ .cipher = { -+ .cia_min_keysize = DES_KEY_SIZE, -+ .cia_max_keysize = DES_KEY_SIZE, -+ .cia_setkey = des_setkey, -+ .cia_encrypt = des_encrypt, -+ .cia_decrypt = des_decrypt, -+ } -+ } -+}; -+ -+static void ecb_des_ciper_loop(u8 *out, u8 *in, unsigned int n) -+{ -+ while (likely(n)) { -+ des_hw_cipher(out, in); -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+ -+static void ecb_des3_ede_encrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n) -+{ -+ while (likely(n)) { -+ des3_hw_ede_encrypt(keys, out, in); -+ -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+ -+static void ecb_des3_ede_decrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n) -+{ -+ while (likely(n)) { -+ des3_hw_ede_decrypt(keys, out, in); -+ -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+ -+#ifdef DES3_EEE -+static void ecb_des3_eee_encrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n) -+{ -+ while (likely(n)) { -+ des3_hw_eee_encrypt(keys, out, in); -+ -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+ -+static void ecb_des3_eee_decrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n) -+{ -+ while (likely(n)) { -+ des3_hw_eee_decrypt(keys, out, in); -+ -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+#endif -+ -+static inline void ecb_des_cipher_n(struct ubicom32_des_ctx *uctx, enum des_ops op, u8 *out, u8 *in, unsigned int n) -+{ -+ switch (op) { -+ case DES_ENCRYPT: -+ case DES_DECRYPT: -+ /* set the right algo, direction and key once */ -+ hw_crypto_set_ctrl(SEC_ALG_DES | (op == DES_ENCRYPT ? SEC_DIR_ENCRYPT : 0)); -+ des_hw_set_key(uctx->key, uctx->key_len); -+ ecb_des_ciper_loop(out, in, n); -+ break; -+ -+ case DES3_EDE_ENCRYPT: -+ ecb_des3_ede_encrypt_loop(uctx->key, out, in, n); -+ break; -+ -+ case DES3_EDE_DECRYPT: -+ ecb_des3_ede_decrypt_loop(uctx->key, out, in, n); -+ break; -+ -+#ifdef DES3_EEE -+ case DES3_EEE_ENCRYPT: -+ ecb_des3_eee_encrypt_loop(uctx->key, out, in, n); -+ break; -+ -+ case DES3_EEE_DECRYPT: -+ ecb_des3_eee_decrypt_loop(uctx->key, out, in, n); -+ break; -+#endif -+ } -+} -+ -+static inline void des_xor_2w(u32 *data, u32 *iv) -+{ -+ data[0] ^= iv[0]; -+ data[1] ^= iv[1]; -+} -+ -+static void cbc_des_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ while (likely(n)) { -+ des_xor_2w((u32 *)in, (u32 *)iv); -+ des_hw_cipher(out, in); -+ SEC_COPY_2W(iv, out); -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+ -+static void cbc_des_decrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ u8 next_iv[DES_BLOCK_SIZE]; -+ while (likely(n)) { -+ SEC_COPY_2W(next_iv, in); -+ des_hw_cipher(out, in); -+ des_xor_2w((u32 *)out, (u32 *)iv); -+ SEC_COPY_2W(iv, next_iv); -+ -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+ -+static void cbc_des3_ede_encrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ while (likely(n)) { -+ des_xor_2w((u32 *)in, (u32 *)iv); -+ des3_hw_ede_encrypt(keys, out, in); -+ SEC_COPY_2W(iv, out); -+ -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+ -+static void cbc_des3_ede_decrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ u8 next_iv[DES_BLOCK_SIZE]; -+ while (likely(n)) { -+ SEC_COPY_2W(next_iv, in); -+ des3_hw_ede_decrypt(keys, out, in); -+ des_xor_2w((u32 *)out, (u32 *)iv); -+ SEC_COPY_2W(iv, next_iv); -+ -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+ -+#ifdef DES3_EEE -+static void cbc_des3_eee_encrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ while (likely(n)) { -+ des_xor_2w((u32 *)in, (u32 *)iv); -+ des3_hw_eee_encrypt(keys, out, in); -+ SEC_COPY_2W(iv, out); -+ -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+ -+static void cbc_des3_eee_decrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ u8 next_iv[DES_BLOCK_SIZE]; -+ while (likely(n)) { -+ SEC_COPY_2W(next_iv, in); -+ des3_hw_eee_decrypt(keys, out, in); -+ des_xor_2w((u32 *)out, (u32 *)iv); -+ SEC_COPY_2W(iv, next_iv); -+ -+ out += DES_BLOCK_SIZE; -+ in += DES_BLOCK_SIZE; -+ n -= DES_BLOCK_SIZE; -+ } -+} -+#endif -+ -+static inline void cbc_des_cipher_n(struct ubicom32_des_ctx *uctx, enum des_ops op, u8 *out, u8 *in, u8 *iv, unsigned int n) -+{ -+ switch (op) { -+ case DES_ENCRYPT: -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT); -+ des_hw_set_key(uctx->key, uctx->key_len); -+ cbc_des_encrypt_loop(out, in, iv, n); -+ break; -+ -+ case DES_DECRYPT: -+ /* set the right algo, direction and key once */ -+ hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT); -+ des_hw_set_key(uctx->key, uctx->key_len); -+ cbc_des_decrypt_loop(out, in, iv, n); -+ break; -+ -+ case DES3_EDE_ENCRYPT: -+ cbc_des3_ede_encrypt_loop(uctx->key, out, in, iv, n); -+ break; -+ -+ case DES3_EDE_DECRYPT: -+ cbc_des3_ede_decrypt_loop(uctx->key, out, in, iv, n); -+ break; -+ -+#ifdef DES3_EEE -+ case DES3_EEE_ENCRYPT: -+ cbc_des3_eee_encrypt_loop(uctx->key, out, in, iv, n); -+ break; -+ -+ case DES3_EEE_DECRYPT: -+ cbc_des3_eee_decrypt_loop(uctx->key, out, in, iv, n); -+ break; -+#endif -+ } -+} -+ -+static int des_cipher(struct blkcipher_desc *desc, struct scatterlist *dst, -+ struct scatterlist *src, unsigned int nbytes, u32 extra_flags, enum des_ops op) -+{ -+ struct ubicom32_des_ctx *uctx = crypto_blkcipher_ctx(desc->tfm); -+ int ret; -+ -+ struct blkcipher_walk walk; -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ ret = blkcipher_walk_virt(desc, &walk); -+ if (ret) { -+ return ret; -+ } -+ -+ hw_crypto_lock(); -+ hw_crypto_check(); -+ -+ while ((nbytes = walk.nbytes)) { -+ /* only use complete blocks */ -+ unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1); -+ u8 *out = walk.dst.virt.addr; -+ u8 *in = walk.src.virt.addr; -+ -+ /* finish n/16 blocks */ -+ if (extra_flags & SEC_CBC_SET) { -+ cbc_des_cipher_n(uctx, op, out, in, walk.iv, n); -+ } else { -+ ecb_des_cipher_n(uctx, op, out, in, n); -+ } -+ -+ nbytes &= DES_BLOCK_SIZE - 1; -+ ret = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ hw_crypto_unlock(); -+ return ret; -+} -+ -+static int ecb_des_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES_ENCRYPT); -+} -+ -+static int ecb_des_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES_DECRYPT); -+} -+ -+static struct crypto_alg ecb_des_alg = { -+ .cra_name = "ecb(des)", -+ .cra_driver_name = "ecb-des-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = DES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_des_ctx), -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = DES_KEY_SIZE, -+ .max_keysize = DES_KEY_SIZE, -+ .setkey = des_setkey, -+ .encrypt = ecb_des_encrypt, -+ .decrypt = ecb_des_decrypt, -+ } -+ } -+}; -+ -+static int cbc_des_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES_ENCRYPT); -+} -+ -+static int cbc_des_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES_DECRYPT); -+} -+ -+static struct crypto_alg cbc_des_alg = { -+ .cra_name = "cbc(des)", -+ .cra_driver_name = "cbc-des-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = DES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_des_ctx), -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = DES_KEY_SIZE, -+ .max_keysize = DES_KEY_SIZE, -+ .ivsize = DES_BLOCK_SIZE, -+ .setkey = des_setkey, -+ .encrypt = cbc_des_encrypt, -+ .decrypt = cbc_des_decrypt, -+ } -+ } -+}; -+ -+/* -+ * RFC2451: -+ * -+ * For DES-EDE3, there is no known need to reject weak or -+ * complementation keys. Any weakness is obviated by the use of -+ * multiple keys. -+ * -+ * However, if the first two or last two independent 64-bit keys are -+ * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the -+ * same as DES. Implementers MUST reject keys that exhibit this -+ * property. -+ * -+ */ -+static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key, -+ unsigned int keylen) -+{ -+ int i, ret; -+ struct ubicom32_des_ctx *dctx = crypto_tfm_ctx(tfm); -+ const u8 *temp_key = key; -+ u32 *flags = &tfm->crt_flags; -+ -+ if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && -+ memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2], -+ DES_KEY_SIZE))) { -+ -+ *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; -+ return -EINVAL; -+ } -+ for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) { -+ ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags); -+ if (ret < 0) -+ return ret; -+ } -+ memcpy(dctx->key, key, keylen); -+ dctx->ctrl = SEC_ALG_DES; //hw 3DES not working yet -+ dctx->key_len = keylen; -+ return 0; -+} -+ -+static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -+{ -+ struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm); -+ -+ hw_crypto_lock(); -+ hw_crypto_check(); -+ -+ des3_hw_ede_encrypt(uctx->key, dst, src); -+ -+ hw_crypto_unlock(); -+} -+ -+static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -+{ -+ struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm); -+ -+ hw_crypto_lock(); -+ hw_crypto_check(); -+ -+ des3_hw_ede_decrypt(uctx->key, dst, src); -+ -+ hw_crypto_unlock(); -+} -+ -+static struct crypto_alg des3_192_alg = { -+ .cra_name = "des3_ede", -+ .cra_driver_name = "des3_ede-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, -+ .cra_blocksize = DES3_192_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_des_ctx), -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list), -+ .cra_u = { -+ .cipher = { -+ .cia_min_keysize = DES3_192_KEY_SIZE, -+ .cia_max_keysize = DES3_192_KEY_SIZE, -+ .cia_setkey = des3_192_setkey, -+ .cia_encrypt = des3_192_encrypt, -+ .cia_decrypt = des3_192_decrypt, -+ } -+ } -+}; -+ -+static int ecb_des3_192_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, unsigned int nbytes) -+{ -+ return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES3_EDE_ENCRYPT); -+} -+ -+static int ecb_des3_192_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, unsigned int nbytes) -+{ -+ return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES3_EDE_DECRYPT); -+} -+ -+static struct crypto_alg ecb_des3_192_alg = { -+ .cra_name = "ecb(des3_ede)", -+ .cra_driver_name = "ecb-des3_ede-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = DES3_192_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_des_ctx), -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT( -+ ecb_des3_192_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = DES3_192_KEY_SIZE, -+ .max_keysize = DES3_192_KEY_SIZE, -+ .setkey = des3_192_setkey, -+ .encrypt = ecb_des3_192_encrypt, -+ .decrypt = ecb_des3_192_decrypt, -+ } -+ } -+}; -+ -+static int cbc_des3_192_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, unsigned int nbytes) -+{ -+ return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES3_EDE_ENCRYPT); -+} -+ -+static int cbc_des3_192_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, unsigned int nbytes) -+{ -+ return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES3_EDE_DECRYPT); -+} -+ -+static struct crypto_alg cbc_des3_192_alg = { -+ .cra_name = "cbc(des3_ede)", -+ .cra_driver_name = "cbc-des3_ede-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = DES3_192_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_des_ctx), -+ .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1, -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT( -+ cbc_des3_192_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = DES3_192_KEY_SIZE, -+ .max_keysize = DES3_192_KEY_SIZE, -+ .ivsize = DES3_192_BLOCK_SIZE, -+ .setkey = des3_192_setkey, -+ .encrypt = cbc_des3_192_encrypt, -+ .decrypt = cbc_des3_192_decrypt, -+ } -+ } -+}; -+ -+static int init(void) -+{ -+ int ret = 0; -+ -+ hw_crypto_init(); -+ -+ ret = crypto_register_alg(&des_alg); -+ if (ret) -+ goto des_err; -+ ret = crypto_register_alg(&ecb_des_alg); -+ if (ret) -+ goto ecb_des_err; -+ ret = crypto_register_alg(&cbc_des_alg); -+ if (ret) -+ goto cbc_des_err; -+ -+ ret = crypto_register_alg(&des3_192_alg); -+ if (ret) -+ goto des3_192_err; -+ ret = crypto_register_alg(&ecb_des3_192_alg); -+ if (ret) -+ goto ecb_des3_192_err; -+ ret = crypto_register_alg(&cbc_des3_192_alg); -+ if (ret) -+ goto cbc_des3_192_err; -+ -+out: -+ return ret; -+ -+cbc_des3_192_err: -+ crypto_unregister_alg(&ecb_des3_192_alg); -+ecb_des3_192_err: -+ crypto_unregister_alg(&des3_192_alg); -+des3_192_err: -+ crypto_unregister_alg(&cbc_des_alg); -+cbc_des_err: -+ crypto_unregister_alg(&ecb_des_alg); -+ecb_des_err: -+ crypto_unregister_alg(&des_alg); -+des_err: -+ goto out; -+} -+ -+static void __exit fini(void) -+{ -+ crypto_unregister_alg(&cbc_des3_192_alg); -+ crypto_unregister_alg(&ecb_des3_192_alg); -+ crypto_unregister_alg(&des3_192_alg); -+ crypto_unregister_alg(&cbc_des_alg); -+ crypto_unregister_alg(&ecb_des_alg); -+ crypto_unregister_alg(&des_alg); -+} -+ -+module_init(init); -+module_exit(fini); -+ -+MODULE_ALIAS("des"); -+MODULE_ALIAS("des3_ede"); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/Makefile linux-2.6.30.10-ubi/arch/ubicom32/crypto/Makefile ---- linux-2.6.30.10/arch/ubicom32/crypto/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/Makefile 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,36 @@ -+# -+# arch/ubicom32/crypto/Makefile -+# -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+obj-$(CONFIG_CRYPTO_UBICOM32) += crypto_ubicom32.o -+obj-$(CONFIG_CRYPTO_AES_UBICOM32) += aes_ubicom32.o -+obj-$(CONFIG_CRYPTO_DES_UBICOM32) += des.o -+obj-$(CONFIG_CRYPTO_MD5_UBICOM32) += md5.o -+obj-$(CONFIG_CRYPTO_SHA1_UBICOM32) += sha1.o -+ -+des-y := des_ubicom32.o des_check_key.o -+md5-y := md5_ubicom32.o md5_ubicom32_asm.o -+sha1-y := sha1_ubicom32.o -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/md5_ubicom32_asm.S linux-2.6.30.10-ubi/arch/ubicom32/crypto/md5_ubicom32_asm.S ---- linux-2.6.30.10/arch/ubicom32/crypto/md5_ubicom32_asm.S 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/md5_ubicom32_asm.S 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,234 @@ -+/* -+ * arch/ubicom32/crypto/md5_ubicom32_asm.S -+ * MD5 (Message Digest 5) support for Ubicom32 v3 architecture -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#define __ASM__ -+#include -+ -+#ifndef RP -+#define RP A5 -+#endif -+ -+;***************************************************************************************** -+; The function prototypes -+;***************************************************************************************** -+; void md5_ip5k_init(void) -+; void md5_ip5k_transform(u32_t *data_input) -+; void md5_get_digest(u32_t *digest) -+ -+;***************************************************************************************** -+; Inputs -+;*****************************************************************************************; -+; data_input is the pointer to the block of data over which the digest will be calculated. -+; It should be word aligned. -+; -+; digest is the pointer to the block of data into which the digest (the output) will be written. -+; It should be word aligned. -+; -+ -+;***************************************************************************************** -+; Outputs -+;***************************************************************************************** -+; None -+ -+;***************************************************************************************** -+; An: Address Registers -+;***************************************************************************************** -+#define an_digest A3 -+#define an_data_input A3 -+#define an_security_block A4 -+ -+;***************************************************************************************** -+; Hash Constants -+;***************************************************************************************** -+#define HASH_MD5_IN0 0x01234567 -+#define HASH_MD5_IN1 0x89abcdef -+#define HASH_MD5_IN2 0xfedcba98 -+#define HASH_MD5_IN3 0x76543210 -+ -+#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2 -+#define HASH_SECURITY_BLOCK_CONTROL_INIT_MD5 ((1 << 4) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION) -+ -+;***************************************************************************************** -+; Hash related defines -+;***************************************************************************************** -+#define hash_control 0x00(an_security_block) -+#define hash_control_low 0x02(an_security_block) -+#define hash_status 0x04(an_security_block) -+ -+#define hash_input_0 0x30(an_security_block) -+#define hash_input_1 0x34(an_security_block) -+#define hash_input_2 0x38(an_security_block) -+#define hash_input_3 0x3c(an_security_block) -+#define hash_input_4 0x40(an_security_block) -+ -+#define hash_output_0 0x70(an_security_block) -+#define hash_output_0_low 0x72(an_security_block) -+#define hash_output_1 0x74(an_security_block) -+#define hash_output_1_low 0x76(an_security_block) -+#define hash_output_2 0x78(an_security_block) -+#define hash_output_2_low 0x7a(an_security_block) -+#define hash_output_3 0x7c(an_security_block) -+#define hash_output_3_low 0x7e(an_security_block) -+ -+;***************************************************************************************** -+; Assembly macros -+;***************************************************************************************** -+ ; C compiler reserves RP (A5) for return address during subroutine call. -+ ; Use RP to return to caller -+.macro call_return_macro -+ calli RP, 0(RP) -+.endm -+ -+#if 0 -+;***************************************************************************************** -+; void md5_ip5k_init(void) -+; initialize the output registers of the hash module -+; -+ ;.section .text.md5_ip5k_init,"ax",@progbits -+ .section .text -+ .global _md5_ip5k_init -+ .func md5_ip5k_init, _md5_ip5k_init -+ -+_md5_ip5k_init: -+ moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS -+ -+ movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5) -+ movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5) -+ -+ movei hash_output_0, #%hi(HASH_MD5_IN0) -+ movei hash_output_0_low, #%lo(HASH_MD5_IN0) -+ -+ movei hash_output_1, #%hi(HASH_MD5_IN1) -+ movei hash_output_1_low, #%lo(HASH_MD5_IN1) -+ -+ movei hash_output_2, #%hi(HASH_MD5_IN2) -+ movei hash_output_2_low, #%lo(HASH_MD5_IN2) -+ -+ movei hash_output_3, #%hi(HASH_MD5_IN3) -+ movei hash_output_3_low, #%lo(HASH_MD5_IN3) -+ -+ call_return_macro -+ .endfunc -+#endif -+ -+;***************************************************************************************** -+; void md5_ip5k_init_digest(u32_t *hash_input) -+; initialize the output registers of the hash module -+ -+ ;.section .text.md5_ip5k_init_digest,"ax",@progbits -+ .section .text -+ .global _md5_ip5k_init_digest -+ .func md5_ip5k_init_digest, _md5_ip5k_init_digest -+ -+_md5_ip5k_init_digest: -+ movea an_data_input, D0 -+ -+ moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS -+ -+ movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5) -+ movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5) -+ -+ move.4 hash_output_0, (an_data_input)4++ -+ move.4 hash_output_1, (an_data_input)4++ -+ move.4 hash_output_2, (an_data_input)4++ -+ move.4 hash_output_3, (an_data_input)4++ -+ -+ call_return_macro -+ .endfunc -+ -+;***************************************************************************************** -+; void md5_ip5k_transform(u32_t *data_input) -+; performs intermediate transformation step for the hash calculation -+; -+ ;.sect .text.md5_ip5k_transform,"ax",@progbits -+ .section .text -+ .global _md5_ip5k_transform -+ .func md5_ip5k_transform, _md5_ip5k_transform -+ -+_md5_ip5k_transform: -+ movea an_data_input, D0 -+ -+ moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS -+ -+ ; Write the first 128bits (16 bytes) -+ move.4 hash_input_0, (an_data_input)4++ -+ move.4 hash_input_1, (an_data_input)4++ -+ move.4 hash_input_2, (an_data_input)4++ -+ move.4 hash_input_3, (an_data_input)4++ -+ move.4 hash_input_4, D0 -+ -+ move.4 hash_input_0, (an_data_input)4++ -+ move.4 hash_input_1, (an_data_input)4++ -+ move.4 hash_input_2, (an_data_input)4++ -+ move.4 hash_input_3, (an_data_input)4++ -+ move.4 hash_input_4, D0 -+ -+ move.4 hash_input_0, (an_data_input)4++ -+ move.4 hash_input_1, (an_data_input)4++ -+ move.4 hash_input_2, (an_data_input)4++ -+ move.4 hash_input_3, (an_data_input)4++ -+ move.4 hash_input_4, D0 -+ -+ move.4 hash_input_0, (an_data_input)4++ -+ move.4 hash_input_1, (an_data_input)4++ -+ move.4 hash_input_2, (an_data_input)4++ -+ move.4 hash_input_3, (an_data_input)4++ -+ move.4 hash_input_4, D0 -+ -+ pipe_flush 0 -+ -+md5_ip5k_transform_wait: -+ ; wait for the module to calculate the output hash -+ btst hash_status, #0 -+ jmpne.f md5_ip5k_transform_wait -+ -+ call_return_macro -+ .endfunc -+ -+;***************************************************************************************** -+; void md5_ip5k_get_digest(u32_t *digest) -+; Return the hash of the input data -+; -+ ;.sect .text.md5_get_digest,"ax",@progbits -+ .section .text -+ .global _md5_ip5k_get_digest -+ .func md5_ip5k_get_digest, _md5_ip5k_get_digest -+ -+_md5_ip5k_get_digest: -+ movea an_digest, D0 -+ -+ moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS -+ -+ ; we have finished -+ move.4 0(an_digest), hash_output_0 -+ move.4 4(an_digest), hash_output_1 -+ move.4 8(an_digest), hash_output_2 -+ move.4 12(an_digest), hash_output_3 -+ -+ call_return_macro -+ .endfunc -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/md5_ubicom32.c linux-2.6.30.10-ubi/arch/ubicom32/crypto/md5_ubicom32.c ---- linux-2.6.30.10/arch/ubicom32/crypto/md5_ubicom32.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/md5_ubicom32.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,200 @@ -+/* -+ * arch/ubicom32/crypto/md5_ubicom32.c -+ * Ubicom32 implementation of the MD5 Secure Hash Algorithm -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+ -+#include "crypto_ubicom32.h" -+ -+#define MD5_DIGEST_SIZE 16 -+#define MD5_BLOCK_SIZE 64 -+#define MD5_HASH_WORDS 4 -+ -+extern void _md5_ip5k_init_digest(u32_t *digest); -+extern void _md5_ip5k_transform(u32_t *data_input); -+extern void _md5_ip5k_get_digest(u32_t *digest); -+ -+struct ubicom32_md5_ctx { -+ u64 count; /* message length */ -+ u32 state[MD5_HASH_WORDS]; -+ u8 buf[2 * MD5_BLOCK_SIZE]; -+}; -+ -+static void md5_init(struct crypto_tfm *tfm) -+{ -+ struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm); -+ mctx->state[0] = 0x01234567; -+ mctx->state[1] = 0x89abcdef; -+ mctx->state[2] = 0xfedcba98; -+ mctx->state[3] = 0x76543210; -+ -+ mctx->count = 0; -+} -+ -+static inline void _md5_process(u32 *digest, const u8 *data) -+{ -+ _md5_ip5k_transform((u32 *)data); -+} -+ -+static void md5_update(struct crypto_tfm *tfm, const u8 *data, -+ unsigned int len) -+{ -+ struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm); -+ int index, clen; -+ -+ /* how much is already in the buffer? */ -+ index = mctx->count & 0x3f; -+ -+ mctx->count += len; -+ -+ if (index + len < MD5_BLOCK_SIZE) { -+ goto store_only; -+ } -+ -+ hw_crypto_lock(); -+ hw_crypto_check(); -+ -+ /* init digest set ctrl register too */ -+ _md5_ip5k_init_digest(mctx->state); -+ -+ if (unlikely(index == 0 && SEC_ALIGNED(data))) { -+fast_process: -+ while (len >= MD5_BLOCK_SIZE) { -+ _md5_process(mctx->state, data); -+ data += MD5_BLOCK_SIZE; -+ len -= MD5_BLOCK_SIZE; -+ } -+ goto store; -+ } -+ -+ /* process one stored block */ -+ if (index) { -+ clen = MD5_BLOCK_SIZE - index; -+ memcpy(mctx->buf + index, data, clen); -+ _md5_process(mctx->state, mctx->buf); -+ data += clen; -+ len -= clen; -+ index = 0; -+ } -+ -+ if (likely(SEC_ALIGNED(data))) { -+ goto fast_process; -+ } -+ -+ /* process as many blocks as possible */ -+ while (len >= MD5_BLOCK_SIZE) { -+ memcpy(mctx->buf, data, MD5_BLOCK_SIZE); -+ _md5_process(mctx->state, mctx->buf); -+ data += MD5_BLOCK_SIZE; -+ len -= MD5_BLOCK_SIZE; -+ } -+ -+store: -+ _md5_ip5k_get_digest(mctx->state); -+ hw_crypto_unlock(); -+ -+store_only: -+ /* anything left? */ -+ if (len) -+ memcpy(mctx->buf + index , data, len); -+} -+ -+/* Add padding and return the message digest. */ -+static void md5_final(struct crypto_tfm *tfm, u8 *out) -+{ -+ struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm); -+ u32 bits[2]; -+ unsigned int index, end; -+ -+ /* must perform manual padding */ -+ index = mctx->count & 0x3f; -+ end = (index < 56) ? MD5_BLOCK_SIZE : (2 * MD5_BLOCK_SIZE); -+ -+ /* start pad with 1 */ -+ mctx->buf[index] = 0x80; -+ -+ /* pad with zeros */ -+ index++; -+ memset(mctx->buf + index, 0x00, end - index - 8); -+ -+ /* append message length */ -+ bits[0] = mctx->count << 3; -+ bits[1] = mctx->count >> 29; -+ __cpu_to_le32s(bits); -+ __cpu_to_le32s(bits + 1); -+ -+ memcpy(mctx->buf + end - 8, &bits, sizeof(bits)); -+ -+ /* force to use the mctx->buf and ignore the partial buf */ -+ mctx->count = mctx->count & ~0x3f; -+ md5_update(tfm, mctx->buf, end); -+ -+ /* copy digest to out */ -+ memcpy(out, mctx->state, MD5_DIGEST_SIZE); -+ -+ /* wipe context */ -+ memset(mctx, 0, sizeof *mctx); -+} -+ -+static struct crypto_alg alg = { -+ .cra_name = "md5", -+ .cra_driver_name= "md5-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST, -+ .cra_blocksize = MD5_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_md5_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(alg.cra_list), -+ .cra_u = { -+ .digest = { -+ .dia_digestsize = MD5_DIGEST_SIZE, -+ .dia_init = md5_init, -+ .dia_update = md5_update, -+ .dia_final = md5_final, -+ } -+ } -+}; -+ -+static int __init init(void) -+{ -+ hw_crypto_init(); -+ return crypto_register_alg(&alg); -+} -+ -+static void __exit fini(void) -+{ -+ crypto_unregister_alg(&alg); -+} -+ -+module_init(init); -+module_exit(fini); -+ -+MODULE_ALIAS("md5"); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("MD5 Secure Hash Algorithm"); -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/sha1_ubicom32_asm.S linux-2.6.30.10-ubi/arch/ubicom32/crypto/sha1_ubicom32_asm.S ---- linux-2.6.30.10/arch/ubicom32/crypto/sha1_ubicom32_asm.S 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/sha1_ubicom32_asm.S 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,244 @@ -+/* -+ * arch/ubicom32/crypto/sha1_ubicom32_asm.S -+ * SHA1 hash support for Ubicom32 architecture V3. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#define __ASM__ -+#include -+ -+#ifndef RP -+#define RP A5 -+#endif -+ -+;***************************************************************************************** -+; The function prototype -+;***************************************************************************************** -+; void sha1_ip5k_init(void) -+; void sha1_ip5k_transform(u32_t *data_input) -+; void sha1_ip5k_output(u32_t *digest) -+ -+;***************************************************************************************** -+; Inputs -+;***************************************************************************************** -+; data_input is the pointer to the block of data over which the digest will be calculated. -+; It should be word aligned. -+; -+; digest is the pointer to the block of data into which the digest (the output) will be written. -+; It should be word aligned. -+; -+ -+;***************************************************************************************** -+; Outputs -+;***************************************************************************************** -+; None -+ -+;***************************************************************************************** -+; Hash Constants -+;***************************************************************************************** -+#define HASH_SHA1_IN0 0x67452301 -+#define HASH_SHA1_IN1 0xefcdab89 -+#define HASH_SHA1_IN2 0x98badcfe -+#define HASH_SHA1_IN3 0x10325476 -+#define HASH_SHA1_IN4 0xc3d2e1f0 -+ -+#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2 -+#define HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1 ((1 << 5) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION) -+ -+;***************************************************************************************** -+; An: Address Registers -+;***************************************************************************************** -+#define an_digest a4 -+#define an_data_input a4 -+#define an_security_block a3 -+ -+;***************************************************************************************** -+; Hash related defines -+;***************************************************************************************** -+#define hash_control 0x00(an_security_block) -+#define hash_control_low 0x02(an_security_block) -+#define hash_status 0x04(an_security_block) -+ -+#define hash_input_0 0x30(an_security_block) -+#define hash_input_1 0x34(an_security_block) -+#define hash_input_2 0x38(an_security_block) -+#define hash_input_3 0x3c(an_security_block) -+#define hash_input_4 0x40(an_security_block) -+ -+#define hash_output_0 0x70(an_security_block) -+#define hash_output_0_low 0x72(an_security_block) -+#define hash_output_1 0x74(an_security_block) -+#define hash_output_1_low 0x76(an_security_block) -+#define hash_output_2 0x78(an_security_block) -+#define hash_output_2_low 0x7a(an_security_block) -+#define hash_output_3 0x7c(an_security_block) -+#define hash_output_3_low 0x7e(an_security_block) -+#define hash_output_4 0x80(an_security_block) -+#define hash_output_4_low 0x82(an_security_block) -+ -+;***************************************************************************************** -+; Assembly macros -+;***************************************************************************************** -+ ; C compiler reserves RP (A5) for return address during subroutine call. -+ ; Use RP to return to caller -+.macro call_return_macro -+ calli RP, 0(RP) -+.endm -+ -+;***************************************************************************************** -+; void sha1_ip5k_init(void) -+; initialize the output registers of the hash module -+ -+ ;.section .text.sha1_ip5k_init,"ax",@progbits -+ .section .ocm_text,"ax",@progbits -+ .global _sha1_ip5k_init -+ .func sha1_ip5k_init, _sha1_ip5k_init -+ -+_sha1_ip5k_init: -+ moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS -+ -+ movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1) -+ movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1) -+ -+ movei hash_output_0, #%hi(HASH_SHA1_IN0) -+ movei hash_output_0_low, #%lo(HASH_SHA1_IN0) -+ -+ movei hash_output_1, #%hi(HASH_SHA1_IN1) -+ movei hash_output_1_low, #%lo(HASH_SHA1_IN1) -+ -+ movei hash_output_2, #%hi(HASH_SHA1_IN2) -+ movei hash_output_2_low, #%lo(HASH_SHA1_IN2) -+ -+ movei hash_output_3, #%hi(HASH_SHA1_IN3) -+ movei hash_output_3_low, #%lo(HASH_SHA1_IN3) -+ -+ movei hash_output_4, #%hi(HASH_SHA1_IN4) -+ movei hash_output_4_low, #%lo(HASH_SHA1_IN4) -+ -+ call_return_macro -+ .endfunc -+ -+;***************************************************************************************** -+; void sha1_ip5k_init_digest(u32_t *hash_input) -+; initialize the output registers of the hash module -+ -+ ;.section .text.sha1_ip5k_init_digest,"ax",@progbits -+ .section .ocm_text,"ax",@progbits -+ .global _sha1_ip5k_init_digest -+ .func sha1_ip5k_init_digest, _sha1_ip5k_init_digest -+ -+_sha1_ip5k_init_digest: -+ movea an_data_input, D0 -+ -+ moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS -+ -+ movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1) -+ movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1) -+ -+ move.4 hash_output_0, (an_data_input)4++ -+ move.4 hash_output_1, (an_data_input)4++ -+ move.4 hash_output_2, (an_data_input)4++ -+ move.4 hash_output_3, (an_data_input)4++ -+ move.4 hash_output_4, (an_data_input)4++ -+ -+ call_return_macro -+ .endfunc -+ -+;***************************************************************************************** -+; void sha1_ip5k_transform(u32_t *data_input) -+; performs intermediate transformation step for the hash calculation -+ -+ ;.section .text.sha1_ip5k_transform,"ax",@progbits -+ .section .ocm_text,"ax",@progbits -+ .global _sha1_ip5k_transform -+ .func sha1_ip5k_transform, _sha1_ip5k_transform -+ -+_sha1_ip5k_transform: -+ movea an_data_input, D0 -+ -+ moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS -+ -+ ; Write the first 128bits (16 bytes) -+ move.4 hash_input_0, (an_data_input)4++ -+ move.4 hash_input_1, (an_data_input)4++ -+ move.4 hash_input_2, (an_data_input)4++ -+ move.4 hash_input_3, (an_data_input)4++ -+ move.4 hash_input_4, D0 -+ -+ move.4 hash_input_0, (an_data_input)4++ -+ move.4 hash_input_1, (an_data_input)4++ -+ move.4 hash_input_2, (an_data_input)4++ -+ move.4 hash_input_3, (an_data_input)4++ -+ move.4 hash_input_4, D0 -+ -+ move.4 hash_input_0, (an_data_input)4++ -+ move.4 hash_input_1, (an_data_input)4++ -+ move.4 hash_input_2, (an_data_input)4++ -+ move.4 hash_input_3, (an_data_input)4++ -+ move.4 hash_input_4, D0 -+ -+ move.4 hash_input_0, (an_data_input)4++ -+ move.4 hash_input_1, (an_data_input)4++ -+ move.4 hash_input_2, (an_data_input)4++ -+ move.4 hash_input_3, (an_data_input)4++ -+ move.4 hash_input_4, D0 -+ -+ pipe_flush 0 -+ -+sha1_ip5k_transform_wait: -+ ; wait for the module to calculate the output hash -+ btst hash_status, #0 -+ jmpne.f sha1_ip5k_transform_wait -+ -+ call_return_macro -+ .endfunc -+ -+;***************************************************************************************** -+; void sha1_ip5k_output(u32_t *digest) -+; Return the hash of the input data -+ -+ ;.section .text.sha1_ip5k_output,"ax",@progbits -+ .section .ocm_text,"ax",@progbits -+ .global _sha1_ip5k_output -+ .func sha1_ip5k_output, _sha1_ip5k_output -+ -+_sha1_ip5k_output: -+ movea an_digest, D0 -+ -+ moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS -+ -+ ; we have finished -+ move.4 0(an_digest), hash_output_0 -+ move.4 4(an_digest), hash_output_1 -+ move.4 8(an_digest), hash_output_2 -+ move.4 12(an_digest), hash_output_3 -+ move.4 16(an_digest), hash_output_4 -+ -+ call_return_macro -+ .endfunc -+ -+;***************************************************************************************** -+;END ;End of program code -+;***************************************************************************************** -diff -ruN linux-2.6.30.10/arch/ubicom32/crypto/sha1_ubicom32.c linux-2.6.30.10-ubi/arch/ubicom32/crypto/sha1_ubicom32.c ---- linux-2.6.30.10/arch/ubicom32/crypto/sha1_ubicom32.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/crypto/sha1_ubicom32.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,354 @@ -+/* -+ * arch/ubicom32/crypto/sha1_ubicom32.c -+ * Ubicom32 implementation of the SHA1 Secure Hash Algorithm. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include "crypto_ubicom32.h" -+#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2 -+#define HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1 ((1 << 5) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION) -+ -+struct ubicom32_sha1_ctx { -+ u64 count; /* message length */ -+ u32 state[5]; -+ u8 buf[2 * SHA1_BLOCK_SIZE]; -+}; -+ -+static inline void sha1_clear_2ws(u8 *buf, int wc) -+{ -+ asm volatile ( -+ "1: move.4 (%0)4++, #0 \n\t" -+ " move.4 (%0)4++, #0 \n\t" -+ " sub.4 %1, #2, %1 \n\t" -+ " jmple.f 1b \n\t" -+ : -+ : "a" (buf), "d" (wc) -+ : "cc" -+ ); -+} -+ -+/* only wipe out count, state, and 1st half of buf - 9 bytes at most */ -+#define sha1_wipe_out(sctx) sha1_clear_2ws((u8 *)sctx, 2 + 5 + 16 - 2) -+ -+static inline void sha1_init_digest(u32 *digest) -+{ -+ hw_crypto_set_ctrl(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1); -+ asm volatile ( -+ " ; move digests to hash_output regs \n\t" -+ " move.4 0x70(%0), 0x0(%1) \n\t" -+ " move.4 0x74(%0), 0x4(%1) \n\t" -+ " move.4 0x78(%0), 0x8(%1) \n\t" -+ " move.4 0x7c(%0), 0xc(%1) \n\t" -+ " move.4 0x80(%0), 0x10(%1) \n\t" -+ : -+ : "a" (SEC_BASE), "a" (digest) -+ ); -+} -+ -+static inline void sha1_transform_feed(const u8 *in) -+{ -+ asm volatile ( -+ " ; write the 1st 16 bytes \n\t" -+ " move.4 0x30(%0), 0x0(%1) \n\t" -+ " move.4 0x34(%0), 0x4(%1) \n\t" -+ " move.4 0x38(%0), 0x8(%1) \n\t" -+ " move.4 0x3c(%0), 0xc(%1) \n\t" -+ " move.4 0x40(%0), %1 \n\t" -+ " ; write the 2nd 16 bytes \n\t" -+ " move.4 0x30(%0), 0x10(%1) \n\t" -+ " move.4 0x34(%0), 0x14(%1) \n\t" -+ " move.4 0x38(%0), 0x18(%1) \n\t" -+ " move.4 0x3c(%0), 0x1c(%1) \n\t" -+ " move.4 0x40(%0), %1 \n\t" -+ " ; write the 3rd 16 bytes \n\t" -+ " move.4 0x30(%0), 0x20(%1) \n\t" -+ " move.4 0x34(%0), 0x24(%1) \n\t" -+ " move.4 0x38(%0), 0x28(%1) \n\t" -+ " move.4 0x3c(%0), 0x2c(%1) \n\t" -+ " move.4 0x40(%0), %1 \n\t" -+ " ; write the 4th 16 bytes \n\t" -+ " move.4 0x30(%0), 0x30(%1) \n\t" -+ " move.4 0x34(%0), 0x34(%1) \n\t" -+ " move.4 0x38(%0), 0x38(%1) \n\t" -+ " move.4 0x3c(%0), 0x3c(%1) \n\t" -+ " move.4 0x40(%0), %1 \n\t" -+ " pipe_flush 0 \n\t" -+ : -+ : "a"(SEC_BASE), "a"(in) -+ ); -+} -+ -+static inline void sha1_transform_wait(void) -+{ -+ asm volatile ( -+ " btst 0x04(%0), #0 \n\t" -+ " jmpne.f -4 \n\t" -+ : -+ : "a"(SEC_BASE) -+ : "cc" -+ ); -+} -+ -+static inline void sha1_output_digest(u32 *digest) -+{ -+ asm volatile ( -+ " move.4 0x0(%1), 0x70(%0) \n\t" -+ " move.4 0x4(%1), 0x74(%0) \n\t" -+ " move.4 0x8(%1), 0x78(%0) \n\t" -+ " move.4 0xc(%1), 0x7c(%0) \n\t" -+ " move.4 0x10(%1), 0x80(%0) \n\t" -+ : -+ : "a" (SEC_BASE), "a" (digest) -+ ); -+} -+ -+static __ocm_text void sha1_init(struct crypto_tfm *tfm) -+{ -+ struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm); -+ -+ sctx->state[0] = SHA1_H0; -+ sctx->state[1] = SHA1_H1; -+ sctx->state[2] = SHA1_H2; -+ sctx->state[3] = SHA1_H3; -+ sctx->state[4] = SHA1_H4; -+ sctx->count = 0; -+} -+ -+static void __ocm_text sha1_update(struct crypto_tfm *tfm, const u8 *data, -+ unsigned int len) -+{ -+ struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm); -+ int index, clen; -+ -+ /* how much is already in the buffer? */ -+ index = sctx->count & 0x3f; -+ -+ sctx->count += len; -+ -+ if (index + len < SHA1_BLOCK_SIZE) { -+ goto store_only; -+ } -+ -+ hw_crypto_lock(); -+ hw_crypto_check(); -+ -+ /* init digest set ctrl register too */ -+ sha1_init_digest(sctx->state); -+ -+ if (unlikely(index == 0 && SEC_ALIGNED(data))) { -+fast_process: -+#if CRYPTO_UBICOM32_LOOP_ASM -+ if (likely(len >= SHA1_BLOCK_SIZE)) { -+ register unsigned int cnt = len >> 6; // loop = len / 64; -+ sha1_transform_feed(data); -+ data += SHA1_BLOCK_SIZE; -+ -+ /* cnt is pre-decremented in the loop */ -+ asm volatile ( -+ "; while (--loop): work on 2nd block \n\t" -+ "1: add.4 %2, #-1, %2 \n\t" -+ " jmpeq.f 5f \n\t" -+ " \n\t" -+ " ; write the 1st 16 bytes \n\t" -+ " move.4 0x30(%1), (%0)4++ \n\t" -+ " move.4 0x34(%1), (%0)4++ \n\t" -+ " move.4 0x38(%1), (%0)4++ \n\t" -+ " move.4 0x3c(%1), (%0)4++ \n\t" -+ " ; can not kick off hw before it \n\t" -+ " ; is done with the prev block \n\t" -+ " \n\t" -+ " btst 0x04(%1), #0 \n\t" -+ " jmpne.f -4 \n\t" -+ " \n\t" -+ " ; tell hw to load 1st 16 bytes \n\t" -+ " move.4 0x40(%1), %2 \n\t" -+ " \n\t" -+ " ; write the 2nd 16 bytes \n\t" -+ " move.4 0x30(%1), (%0)4++ \n\t" -+ " move.4 0x34(%1), (%0)4++ \n\t" -+ " move.4 0x38(%1), (%0)4++ \n\t" -+ " move.4 0x3c(%1), (%0)4++ \n\t" -+ " move.4 0x40(%1), %2 \n\t" -+ " \n\t" -+ " ; write the 3rd 16 bytes \n\t" -+ " move.4 0x30(%1), (%0)4++ \n\t" -+ " move.4 0x34(%1), (%0)4++ \n\t" -+ " move.4 0x38(%1), (%0)4++ \n\t" -+ " move.4 0x3c(%1), (%0)4++ \n\t" -+ " move.4 0x40(%1), %2 \n\t" -+ " \n\t" -+ " ; write the 4th 16 bytes \n\t" -+ " move.4 0x30(%1), (%0)4++ \n\t" -+ " move.4 0x34(%1), (%0)4++ \n\t" -+ " move.4 0x38(%1), (%0)4++ \n\t" -+ " move.4 0x3c(%1), (%0)4++ \n\t" -+ " move.4 0x40(%1), %2 \n\t" -+ " \n\t" -+ "; no need flush, enough insts \n\t" -+ "; before next hw wait \n\t" -+ " \n\t" -+ "; go back to loop \n\t" -+ " jmpt 1b \n\t" -+ " \n\t" -+ "; wait hw for last block \n\t" -+ "5: btst 0x04(%1), #0 \n\t" -+ " jmpne.f -4 \n\t" -+ " \n\t" -+ : "+a" (data) -+ : "a"( SEC_BASE), "d" (cnt) -+ : "cc" -+ ); -+ -+ len = len & (64 - 1); -+ } -+#else -+ while (likely(len >= SHA1_BLOCK_SIZE)) { -+ sha1_transform_feed(data); -+ data += SHA1_BLOCK_SIZE; -+ len -= SHA1_BLOCK_SIZE; -+ sha1_transform_wait(); -+ } -+#endif -+ goto store; -+ } -+ -+ /* process one stored block */ -+ if (index) { -+ clen = SHA1_BLOCK_SIZE - index; -+ memcpy(sctx->buf + index, data, clen); -+ sha1_transform_feed(sctx->buf); -+ data += clen; -+ len -= clen; -+ index = 0; -+ sha1_transform_wait(); -+ } -+ -+ if (likely(SEC_ALIGNED(data))) { -+ goto fast_process; -+ } -+ -+ /* process as many blocks as possible */ -+ if (likely(len >= SHA1_BLOCK_SIZE)) { -+ memcpy(sctx->buf, data, SHA1_BLOCK_SIZE); -+ do { -+ sha1_transform_feed(sctx->buf); -+ data += SHA1_BLOCK_SIZE; -+ len -= SHA1_BLOCK_SIZE; -+ if (likely(len >= SHA1_BLOCK_SIZE)) { -+ memcpy(sctx->buf, data, SHA1_BLOCK_SIZE); -+ sha1_transform_wait(); -+ continue; -+ } -+ /* it is the last block */ -+ sha1_transform_wait(); -+ break; -+ } while (1); -+ } -+ -+store: -+ sha1_output_digest(sctx->state); -+ hw_crypto_unlock(); -+ -+store_only: -+ /* anything left? */ -+ if (len) -+ memcpy(sctx->buf + index , data, len); -+} -+ -+/* Add padding and return the message digest. */ -+static void __ocm_text sha1_final(struct crypto_tfm *tfm, u8 *out) -+{ -+ struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm); -+ u64 bits; -+ unsigned int index, end; -+ -+ /* must perform manual padding */ -+ index = sctx->count & 0x3f; -+ end = (index < 56) ? SHA1_BLOCK_SIZE : (2 * SHA1_BLOCK_SIZE); -+ -+ /* start pad with 1 */ -+ sctx->buf[index] = 0x80; -+ -+ /* pad with zeros */ -+ index++; -+ memset(sctx->buf + index, 0x00, end - index - 8); -+ -+ /* append message length */ -+ bits = sctx->count << 3 ; -+ SEC_COPY_2W(sctx->buf + end - 8, &bits); -+ -+ /* force to use the sctx->buf and ignore the partial buf */ -+ sctx->count = sctx->count & ~0x3f; -+ sha1_update(tfm, sctx->buf, end); -+ -+ /* copy digest to out */ -+ SEC_COPY_5W(out, sctx->state); -+ -+ /* wipe context */ -+ sha1_wipe_out(sctx); -+} -+ -+static struct crypto_alg alg = { -+ .cra_name = "sha1", -+ .cra_driver_name= "sha1-ubicom32", -+ .cra_priority = CRYPTO_UBICOM32_PRIORITY, -+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST, -+ .cra_blocksize = SHA1_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct ubicom32_sha1_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(alg.cra_list), -+ .cra_u = { -+ .digest = { -+ .dia_digestsize = SHA1_DIGEST_SIZE, -+ .dia_init = sha1_init, -+ .dia_update = sha1_update, -+ .dia_final = sha1_final, -+ } -+ } -+}; -+ -+static int __init init(void) -+{ -+ hw_crypto_init(); -+ return crypto_register_alg(&alg); -+} -+ -+static void __exit fini(void) -+{ -+ crypto_unregister_alg(&alg); -+} -+ -+module_init(init); -+module_exit(fini); -+ -+MODULE_ALIAS("sha1"); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/a.out.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/a.out.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/a.out.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/a.out.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,47 @@ -+/* -+ * arch/ubicom32/include/asm/a.out.h -+ * Definitions for Ubicom32 a.out executable format. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_A_OUT_H -+#define _ASM_UBICOM32_A_OUT_H -+ -+struct exec -+{ -+ unsigned long a_info; /* Use macros N_MAGIC, etc for access */ -+ unsigned a_text; /* length of text, in bytes */ -+ unsigned a_data; /* length of data, in bytes */ -+ unsigned a_bss; /* length of uninitialized data area for file, in bytes */ -+ unsigned a_syms; /* length of symbol table data in file, in bytes */ -+ unsigned a_entry; /* start address */ -+ unsigned a_trsize; /* length of relocation info for text, in bytes */ -+ unsigned a_drsize; /* length of relocation info for data, in bytes */ -+}; -+ -+#define N_TRSIZE(a) ((a).a_trsize) -+#define N_DRSIZE(a) ((a).a_drsize) -+#define N_SYMSIZE(a) ((a).a_syms) -+ -+#endif /* _ASM_UBICOM32_A_OUT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/atomic.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/atomic.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/atomic.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/atomic.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,348 @@ -+/* -+ * arch/ubicom32/include/asm/atomic.h -+ * Atomic operations definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_ATOMIC_H -+#define _ASM_UBICOM32_ATOMIC_H -+ -+#include -+#include -+#include -+ -+/* -+ * Most instructions on the Ubicom32 processor are atomic in that they -+ * execute in one clock cycle. However, Linux has several operations -+ * (e.g. compare and swap) which will require more than a single instruction -+ * to perform. To achieve this, the Ubicom32 processor uses a single -+ * global bit in a scratchpad register as a critical section lock. All -+ * atomic operations acquire this lock. -+ * -+ * NOTE: To AVOID DEADLOCK(s), the atomic lock must only be used for atomic -+ * operations or by the ldsr to avoid disabling a thread performing an atomic -+ * operation. -+ * -+ * Do not attempt to disable interrupts while holding the atomic operations -+ * lock or you will DEADLOCK the system. -+ */ -+ -+#define ATOMIC_INIT(i) { (i) } -+ -+/* -+ * __atomic_add() -+ * Add i to v and return the result. -+ */ -+static inline void __atomic_add(int i, atomic_t *v) -+{ -+ atomic_t *vt = v; -+ -+ __atomic_lock_acquire(); -+ vt->counter += i; -+ __atomic_lock_release(); -+} -+ -+/* -+ * __atomic_sub() -+ * Subtract i from v and return the result. -+ */ -+static inline void __atomic_sub(int i, atomic_t *v) -+{ -+ atomic_t *vt = v; -+ -+ __atomic_lock_acquire(); -+ vt->counter -= i; -+ __atomic_lock_release(); -+} -+ -+/* -+ * __atomic_add_return() -+ * Add i to v and return the result. -+ * -+ * The implementation here looks rather odd because we appear to be doing -+ * the addition twice. In fact that's exactly what we're doing but with -+ * the ubicom32 instruction set we can do the inner load and add with two -+ * instructions whereas generating both the atomic result and the "ret" -+ * result requires three instructions. The second add is generally only as -+ * costly as a move instruction and in cases where we compare the result -+ * with a constant the compiler can fold two constant values and do a -+ * single instruction, thus saving an instruction overall! -+ * -+ * At the worst we save one instruction inside the atomic lock. -+ */ -+static inline int __atomic_add_return(int i, atomic_t *v) -+{ -+ int ret; -+ atomic_t *vt = v; -+ -+ __atomic_lock_acquire(); -+ ret = vt->counter; -+ vt->counter = ret + i; -+ __atomic_lock_release(); -+ -+ return ret + i; -+} -+ -+/* -+ * __atomic_sub_return() -+ * Subtract i from v and return the result. -+ * -+ * The implementation here looks rather odd because we appear to be doing -+ * the subtraction twice. In fact that's exactly what we're doing but with -+ * the ubicom32 instruction set we can do the inner load and sub with two -+ * instructions whereas generating both the atomic result and the "ret" -+ * result requires three instructions. The second sub is generally only as -+ * costly as a move instruction and in cases where we compare the result -+ * with a constant the compiler can fold two constant values and do a -+ * single instruction, thus saving an instruction overall! -+ * -+ * At the worst we save one instruction inside the atomic lock. -+ */ -+static inline int __atomic_sub_return(int i, atomic_t *v) -+{ -+ int ret; -+ atomic_t *vt = v; -+ -+ __atomic_lock_acquire(); -+ ret = vt->counter; -+ vt->counter = ret - i; -+ __atomic_lock_release(); -+ -+ return ret - i; -+} -+ -+/* -+ * PUBLIC API FOR ATOMIC! -+ */ -+#define atomic_add(i,v) (__atomic_add( ((int)i),(v))) -+#define atomic_sub(i,v) (__atomic_sub( ((int)i),(v))) -+#define atomic_inc(v) (__atomic_add( 1,(v))) -+#define atomic_dec(v) (__atomic_sub( 1,(v))) -+#define atomic_add_return(i,v) (__atomic_add_return( ((int)i),(v))) -+#define atomic_sub_return(i,v) (__atomic_sub_return( ((int)i),(v))) -+#define atomic_inc_return(v) (__atomic_add_return( 1,(v))) -+#define atomic_dec_return(v) (__atomic_sub_return( 1,(v))) -+#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) -+#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) -+#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) -+#define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0) -+ -+/* -+ * atomic_read() -+ * Acquire the atomic lock and read the variable. -+ */ -+static inline int atomic_read(const atomic_t *v) -+{ -+ int ret; -+ const atomic_t *vt = v; -+ -+ __atomic_lock_acquire(); -+ ret = vt->counter; -+ __atomic_lock_release(); -+ -+ return ret; -+} -+ -+/* -+ * atomic_set() -+ * Acquire the atomic lock and set the variable. -+ */ -+static inline void atomic_set(atomic_t *v, int i) -+{ -+ atomic_t *vt = v; -+ -+ __atomic_lock_acquire(); -+ vt->counter = i; -+ __atomic_lock_release(); -+} -+ -+/* -+ * atomic_cmpxchg -+ * Acquire the atomic lock and exchange if current == old. -+ */ -+static inline int atomic_cmpxchg(atomic_t *v, int old, int new) -+{ -+ int prev; -+ atomic_t *vt = v; -+ -+ __atomic_lock_acquire(); -+ prev = vt->counter; -+ if (prev == old) { -+ vt->counter = new; -+ } -+ __atomic_lock_release(); -+ -+ return prev; -+} -+ -+/* -+ * atomic_xchg() -+ * Acquire the atomic lock and exchange values. -+ */ -+static inline int atomic_xchg(atomic_t *v, int new) -+{ -+ int prev; -+ atomic_t *vt = v; -+ -+ __atomic_lock_acquire(); -+ prev = vt->counter; -+ vt->counter = new; -+ __atomic_lock_release(); -+ -+ return prev; -+} -+ -+/* -+ * atomic_add_unless() -+ * Acquire the atomic lock and add a unless the value is u. -+ */ -+static inline int atomic_add_unless(atomic_t *v, int a, int u) -+{ -+ int prev; -+ atomic_t *vt = v; -+ -+ __atomic_lock_acquire(); -+ prev = vt->counter; -+ if (prev != u) { -+ vt->counter += a; -+ __atomic_lock_release(); -+ return 1; -+ } -+ -+ __atomic_lock_release(); -+ return 0; -+} -+ -+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) -+ -+#include -+ -+/* -+ * The following is not a real function. The compiler should remove the function -+ * call as long as the user does not pass in a size that __xchg and __cmpxchg -+ * are not prepared for. If the user does pass in an unknown size, the user -+ * will get a link time error. -+ * -+ * The no return is to prevent a compiler error that can occur when dealing with -+ * uninitialized variables. Given that the function doesn't exist there is no -+ * net effect (and if it did it would not return). -+ */ -+extern void __xchg_called_with_bad_pointer(void) __attribute__((noreturn)); -+ -+/* -+ * __xchg() -+ * Xchange *ptr for x atomically. -+ * -+ * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an -+ * atomic exchange instruction so we use the global atomic_lock. -+ */ -+static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) -+{ -+ unsigned long ret; -+ -+ __atomic_lock_acquire(); -+ -+ switch (size) { -+ case 1: -+ ret = *(volatile unsigned char *)ptr; -+ *(volatile unsigned char *)ptr = x; -+ break; -+ -+ case 2: -+ ret = *(volatile unsigned short *)ptr; -+ *(volatile unsigned short *)ptr = x; -+ break; -+ -+ case 4: -+ ret = *(volatile unsigned int *)ptr; -+ *(volatile unsigned int *)ptr = x; -+ break; -+ -+ default: -+ __xchg_called_with_bad_pointer(); -+ break; -+ } -+ __atomic_lock_release(); -+ return ret; -+} -+ -+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) -+ -+/* -+ * __cmpxchg() -+ * Compare and Xchange *ptr for x atomically. -+ * -+ * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an -+ * atomic exchange instruction so we use the global atomic_lock. -+ */ -+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long next, int size) -+{ -+ unsigned long prev; -+ -+ __atomic_lock_acquire(); -+ switch (size) { -+ case 1: -+ prev = *(u8 *)ptr; -+ if (prev == old) { -+ *(u8 *)ptr = (u8)next; -+ } -+ break; -+ -+ case 2: -+ prev = *(u16 *)ptr; -+ if (prev == old) { -+ *(u16 *)ptr = (u16)next; -+ } -+ break; -+ -+ case 4: -+ prev = *(u32 *)ptr; -+ if (prev == old) { -+ *(u32 *)ptr = (u32)next; -+ } -+ break; -+ -+ default: -+ __xchg_called_with_bad_pointer(); -+ break; -+ } -+ __atomic_lock_release(); -+ return prev; -+} -+ -+/* -+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make -+ * them available. -+ */ -+#define cmpxchg_local(ptr, o, n) \ -+ ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), sizeof(*(ptr)))) -+ -+#define cmpxchg(ptr, o, n) __cmpxchg((ptr), (o), (n), sizeof(*(ptr))) -+ -+#define smp_mb__before_atomic_inc() asm volatile ("" : : : "memory") -+#define smp_mb__after_atomic_inc() asm volatile ("" : : : "memory") -+#define smp_mb__before_atomic_dec() asm volatile ("" : : : "memory") -+#define smp_mb__after_atomic_dec() asm volatile ("" : : : "memory") -+ -+#endif /* _ASM_UBICOM32_ATOMIC_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/audio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/audio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/audio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/audio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,40 @@ -+/* -+ * arch/ubicom32/include/asm/audio.h -+ * Audio include file -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#ifndef _AUDIO_H -+#define _AUDIO_H -+ -+#include -+#include -+ -+/* -+ * Resource indices used to access IRQs via platform_get_resource -+ */ -+#define AUDIO_MEM_RESOURCE 0 -+#define AUDIO_TX_IRQ_RESOURCE 0 -+#define AUDIO_RX_IRQ_RESOURCE 1 -+ -+extern struct platform_device * __init audio_device_alloc(const char *driver_name, const char *node_name, const char *inst_name, int priv_size); -+ -+#define audio_device_priv(pdev) (((struct ubi32pcm_platform_data *)(((struct platform_device *)(pdev))->dev.platform_data))->priv_data) -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/audionode.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/audionode.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/audionode.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/audionode.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,152 @@ -+/* -+ * audionode.h -+ * audionode and DMA descriptors -+ * -+ * Copyright © 2009 Ubicom Inc. . All rights reserved. -+ * -+ * This file contains confidential information of Ubicom, Inc. and your use of -+ * this file is subject to the Ubicom Software License Agreement distributed with -+ * this file. If you are uncertain whether you are an authorized user or to report -+ * any unauthorized use, please contact Ubicom, Inc. at +1-408-789-2200. -+ * Unauthorized reproduction or distribution of this file is subject to civil and -+ * criminal penalties. -+ * -+ */ -+#ifndef _AUDIONODE_H_ -+#define _AUDIONODE_H_ -+ -+#define AUDIO_INT_FLAG_MORE_SAMPLES 0x00000001 -+#define AUDIO_INT_FLAG_COMMAND 0x00000002 -+ -+/* -+ * Commands the Primary OS sends to the audio device -+ */ -+enum audio_command { -+ AUDIO_CMD_NONE, -+ AUDIO_CMD_START, -+ AUDIO_CMD_STOP, -+ AUDIO_CMD_PAUSE, -+ AUDIO_CMD_RESUME, -+ AUDIO_CMD_MUTE, -+ AUDIO_CMD_UNMUTE, -+ AUDIO_CMD_SETUP, -+ AUDIO_CMD_ENABLE, -+ AUDIO_CMD_DISABLE, -+}; -+ -+/* -+ * Flag bits passed in the registers -+ */ -+#define CMD_START_FLAG_LE (1 << 0) /* Use Little Endian Mode */ -+ -+/* -+ * Status bits that audio device can set to indicate reason -+ * for interrupting the Primary OS -+ */ -+#define AUDIO_STATUS_PLAY_DMA0_REQUEST (1 << 0) /* Audio device needs samples in DMA0 for playback */ -+#define AUDIO_STATUS_PLAY_DMA1_REQUEST (1 << 1) /* Audio device needs samples in DMA1 for playback */ -+ -+struct audio_dma { -+ /* -+ * NOTE: The active flag shall only be SET by the producer and CLEARED -+ * by the consumer, NEVER the other way around. For playback, the -+ * Primary OS sets this flag and ipAudio clears it. -+ * -+ * The producer shall not modify the ptr or ctr fields when the transfer -+ * is marked as active, as these are used by the consumer to do the -+ * transfer. -+ */ -+ volatile u32_t active; /* Nonzero if data in ptr/ctr ready to be transferred */ -+ volatile void *ptr; /* Pointer to data to be transferred */ -+ volatile u32_t ctr; /* Counter: number of data units to transfer */ -+}; -+ -+#define AUDIONODE_CAP_BE (1 << 0) -+#define AUDIONODE_CAP_LE (1 << 1) -+ -+#define AUDIONODE_VERSION 7 -+struct audio_node { -+ struct devtree_node dn; -+ -+ /* -+ * Version of this node -+ */ -+ u32_t version; -+ -+ /* -+ * Pointer to the registers -+ */ -+ struct audio_regs *regs; -+}; -+ -+/* -+ * [OCM] Audio registers -+ * Registers exposed as part of our MMIO area -+ */ -+#define AUDIO_REGS_VERSION 7 -+struct audio_regs { -+ /* -+ * Version of this register set -+ */ -+ u32_t version; -+ -+ /* -+ * Interrupt status -+ */ -+ volatile u32_t int_status; -+ -+ /* -+ * Interrupt request -+ */ -+ volatile u32_t int_req; -+ -+ /* -+ * Current IRQ being serviced -+ */ -+ u32_t cur_irq; -+ -+ /* -+ * Maximum number of devices supported -+ */ -+ u32_t max_devs; -+ -+ /* -+ * [DDR] Device registers for each of the devices -+ */ -+ struct audio_dev_regs *adr; -+}; -+ -+#define AUDIO_DEV_REGS_VERSION 2 -+struct audio_dev_regs { -+ u32_t version; /* Version of this register set */ -+ -+ u8_t name[32]; /* Name of this driver */ -+ u32_t caps; /* Capabilities of this driver */ -+ const u32_t *sample_rates; /* Sample Rates supported by this driver */ -+ u32_t n_sample_rates; /* Number of sample rates supported by this driver */ -+ u32_t channel_mask; /* A bit set in a particular position means we support this channel configuration */ -+ volatile u32_t int_flags; /* Reason for interrupting audio device */ -+ volatile enum audio_command command; /* Command from Primary OS */ -+ volatile u32_t flags; /* Flag bits for this command */ -+ volatile u32_t channels; /* Number of channels */ -+ volatile u32_t sample_rate; /* Sample rate */ -+ volatile u32_t status; /* Status bits sent from ipAudio to Primary OS */ -+ void *primary_os_buffer_ptr; /* -+ * Playback: Pointer to next sample to be removed from -+ * Primary OS sample buffer -+ * Capture: Pointer to where next sample will be inserted -+ * into Primary OS sample buffer -+ */ -+ -+ /* -+ * These are the transfer requests. They are used in alternating -+ * order so that when ipAudio is processing one request, the -+ * Primary OS can fill in the other one. -+ * -+ * NOTE: The active bit shall always be SET by the producer and -+ * CLEARED by the consumer, NEVER the other way around. -+ */ -+ struct audio_dma dma_xfer_requests[2]; -+}; -+ -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/auxvec.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/auxvec.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/auxvec.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/auxvec.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,32 @@ -+/* -+ * arch/ubicom32/include/asm/auxvec.h -+ * Symbolic values for the entries in the auxiliary table -+ * put on the initial stack. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_AUXVEC_H -+#define _ASM_UBICOM32_AUXVEC_H -+ -+#endif /* _ASM_UBICOM32_AUXVEC_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/bitops.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bitops.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/bitops.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bitops.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,172 @@ -+/* -+ * arch/ubicom32/include/asm/bitops.h -+ * Bit manipulation definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_BITOPS_H -+#define _ASM_UBICOM32_BITOPS_H -+ -+/* -+ * Copyright 1992, Linus Torvalds. -+ */ -+ -+#include -+#include /* swab32 */ -+ -+#ifdef __KERNEL__ -+ -+#ifndef _LINUX_BITOPS_H -+#error only can be included directly -+#endif -+ -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+static inline void set_bit(int bit, volatile unsigned long *p) -+{ -+ unsigned long mask = 1UL << (bit & 31); -+ -+ p += bit >> 5; -+ -+ __atomic_lock_acquire(); -+ *p |= mask; -+ __atomic_lock_release(); -+} -+ -+static inline void clear_bit(int bit, volatile unsigned long *p) -+{ -+ unsigned long mask = 1UL << (bit & 31); -+ -+ p += bit >> 5; -+ -+ __atomic_lock_acquire(); -+ *p &= ~mask; -+ __atomic_lock_release(); -+} -+ -+/* -+ * clear_bit() doesn't provide any barrier for the compiler. -+ */ -+#define smp_mb__before_clear_bit() barrier() -+#define smp_mb__after_clear_bit() barrier() -+ -+static inline void change_bit(int bit, volatile unsigned long *p) -+{ -+ unsigned long mask = 1UL << (bit & 31); -+ -+ p += bit >> 5; -+ -+ __atomic_lock_acquire(); -+ *p ^= mask; -+ __atomic_lock_release(); -+} -+ -+static inline int test_and_set_bit(int bit, volatile unsigned long *p) -+{ -+ unsigned int res; -+ unsigned long mask = 1UL << (bit & 31); -+ -+ p += bit >> 5; -+ -+ __atomic_lock_acquire(); -+ res = *p; -+ *p = res | mask; -+ __atomic_lock_release(); -+ -+ return res & mask; -+} -+ -+static inline int test_and_clear_bit(int bit, volatile unsigned long *p) -+{ -+ unsigned int res; -+ unsigned long mask = 1UL << (bit & 31); -+ -+ p += bit >> 5; -+ -+ __atomic_lock_acquire(); -+ res = *p; -+ *p = res & ~mask; -+ __atomic_lock_release(); -+ -+ return res & mask; -+} -+ -+static inline int test_and_change_bit(int bit, volatile unsigned long *p) -+{ -+ unsigned int res; -+ unsigned long mask = 1UL << (bit & 31); -+ -+ p += bit >> 5; -+ -+ __atomic_lock_acquire(); -+ res = *p; -+ *p = res ^ mask; -+ __atomic_lock_release(); -+ -+ return res & mask; -+} -+ -+#include -+ -+/* -+ * This routine doesn't need to be atomic. -+ */ -+static inline int __constant_test_bit(int nr, const volatile unsigned long *addr) -+{ -+ return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; -+} -+ -+static inline int __test_bit(int nr, const volatile unsigned long *addr) -+{ -+ int * a = (int *) addr; -+ int mask; -+ -+ a += nr >> 5; -+ mask = 1 << (nr & 0x1f); -+ return ((mask & *a) != 0); -+} -+ -+#define test_bit(nr,addr) (__builtin_constant_p(nr) ? __constant_test_bit((nr),(addr)) : __test_bit((nr),(addr))) -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#endif /* __KERNEL__ */ -+ -+#include -+#include -+#include -+ -+#endif /* _ASM_UBICOM32_BITOPS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/board.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/board.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/board.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/board.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,34 @@ -+/* -+ * arch/ubicom32/include/asm/board.h -+ * Board init and revision definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_BOARD_H -+#define _ASM_UBICOM32_BOARD_H -+ -+extern const char *board_get_revision(void); -+extern void __init board_init(void); -+ -+#endif /* _ASM_UBICOM32_BOARD_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/bootargs.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bootargs.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/bootargs.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bootargs.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,34 @@ -+/* -+ * arch/ubicom32/include/asm/bootargs.h -+ * Kernel command line via the devtree API. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_BOOTARGS_H -+#define _ASM_UBICOM32_BOOTARGS_H -+ -+extern const char *bootargs_get_cmdline(void); -+extern void __init bootargs_init(void); -+ -+#endif /* _ASM_UBICOM32_BOOTARGS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/bootinfo.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bootinfo.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/bootinfo.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bootinfo.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,34 @@ -+/* -+ * arch/ubicom32/include/asm/bootinfo.h -+ * Definitions of firmware boot parameters passed to the kernel. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_BOOTINFO_H -+#define _ASM_UBICOM32_BOOTINFO_H -+ -+/* Nothing for ubicom32 */ -+ -+#endif /* _ASM_UBICOM32_BOOTINFO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/bug.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bug.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/bug.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bug.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,95 @@ -+/* -+ * arch/ubicom32/include/asm/bug.h -+ * Generic bug.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_BUG_H -+#define _ASM_UBICOM32_BUG_H -+ -+#include -+#include -+ -+#if defined(CONFIG_BUG) && defined(CONFIG_STOP_ON_BUG) -+ -+/* -+ * BUG() -+ * Ubicom specific version of the BUG() macro. -+ * -+ * This implementation performs a THREAD_STALL stopping all threads before -+ * calling panic. This enables a developer to see the "real" state of the -+ * machine (since panic alters the system state). We do the printf first -+ * because while it is slow, it does not alter system state (like -+ * interrupts). -+ * -+ * TODO: Implement the trap sequence used by other architectures. -+ */ -+#define BUG() do { \ -+ printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ -+ THREAD_STALL; \ -+ panic("BUG!"); \ -+} while (0) -+ -+ -+/* -+ * __WARN() -+ * WARN() using printk() for now. -+ * -+ * TODO: Implement the trap sequence used by other architectures. -+ */ -+#define __WARN() \ -+ do { \ -+ printk("WARN: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ -+ } while(0) -+ -+/* -+ * WARN_ON() -+ * Ubicom specific version of the WARN_ON macro. -+ * -+ * This implementation performs a printk for the WARN_ON() instead -+ * of faulting into the kernel and using report_bug(). -+ * -+ * TODO: Implement the trap sequence used by other architectures. -+ */ -+#define WARN_ON(x) ({ \ -+ int __ret_warn_on = !!(x); \ -+ if (__builtin_constant_p(__ret_warn_on)) { \ -+ if (__ret_warn_on) \ -+ __WARN(); \ -+ } else { \ -+ if (unlikely(__ret_warn_on)) \ -+ __WARN(); \ -+ } \ -+ unlikely(__ret_warn_on); \ -+}) -+ -+ -+#define HAVE_ARCH_BUG -+#define HAVE_ARCH_WARN_ON -+ -+#endif -+ -+#include -+ -+#endif /* _ASM_UBICOM32_BUG_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/bugs.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bugs.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/bugs.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/bugs.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,44 @@ -+/* -+ * arch/ubicom32/include/asm/bugs.h -+ * Definition of check_bugs() for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1994 Linus Torvalds -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+/* -+ * This is included by init/main.c to check for architecture-dependent bugs. -+ * -+ * Needs: -+ * void check_bugs(void); -+ */ -+ -+#ifndef _ASM_UBICOM32_BUGS_H -+#define _ASM_UBICOM32_BUGS_H -+ -+static void check_bugs(void) -+{ -+} -+ -+#endif /* _ASM_UBICOM32_BUGS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/byteorder.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/byteorder.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/byteorder.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/byteorder.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/byteorder.h -+ * Byte order swapping utility routines. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_BYTEORDER_H -+#define _ASM_UBICOM32_BYTEORDER_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_BYTEORDER_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/cachectl.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cachectl.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/cachectl.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cachectl.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,39 @@ -+/* -+ * arch/ubicom32/include/asm/cachectl.h -+ * Ubicom32 cache control definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_CACHECTL_H -+#define _ASM_UBICOM32_CACHECTL_H -+ -+#include -+ -+/* -+ * mem_cache_control() -+ * Special cache control operation -+ */ -+extern void mem_cache_control(unsigned long cc, unsigned long begin_addr, unsigned long end_addr, unsigned long op); -+ -+#endif /* _ASM_UBICOM32_CACHECTL_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/cacheflush.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cacheflush.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/cacheflush.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cacheflush.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,111 @@ -+/* -+ * arch/ubicom32/include/asm/cacheflush.h -+ * Cache flushing definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_CACHEFLUSH_H -+#define _ASM_UBICOM32_CACHEFLUSH_H -+ -+/* -+ * (C) Copyright 2000-2004, Greg Ungerer -+ */ -+#include -+#include -+#include -+ -+#define flush_cache_all() __flush_cache_all() -+#define flush_cache_mm(mm) do { } while (0) -+#define flush_cache_dup_mm(mm) do { } while (0) -+#define flush_cache_range(vma, start, end) __flush_cache_all() -+#define flush_cache_page(vma, vmaddr) do { } while (0) -+#define flush_dcache_page(page) do { } while (0) -+#define flush_dcache_mmap_lock(mapping) do { } while (0) -+#define flush_dcache_mmap_unlock(mapping) do { } while (0) -+ -+#define flush_dcache_range(start, end) \ -+do { \ -+ /* Flush the data cache and invalidate the I cache. */ \ -+ mem_cache_control(DCCR_BASE, start, end, CCR_CTRL_FLUSH_ADDR); \ -+ mem_cache_control(ICCR_BASE, start, end, CCR_CTRL_INV_ADDR); \ -+} while (0) -+ -+#define flush_icache_range(start, end) \ -+do { \ -+ /* Flush the data cache and invalidate the I cache. */ \ -+ mem_cache_control(DCCR_BASE, start, end, CCR_CTRL_FLUSH_ADDR); \ -+ mem_cache_control(ICCR_BASE, start, end, CCR_CTRL_INV_ADDR); \ -+} while (0) -+ -+#define flush_icache_page(vma,pg) do { } while (0) -+#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) -+#define flush_cache_vmap(start, end) do { } while (0) -+#define flush_cache_vunmap(start, end) do { } while (0) -+ -+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ -+ memcpy(dst, src, len) -+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ -+ memcpy(dst, src, len) -+ -+/* -+ * Cache handling for IP5000 -+ */ -+extern inline void mem_cache_invalidate_all(unsigned long cc) -+{ -+ if (cc == DCCR_BASE) -+ UBICOM32_LOCK(DCCR_LOCK_BIT); -+ else -+ UBICOM32_LOCK(ICCR_LOCK_BIT); -+ -+ asm volatile ( -+ " bset "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_RESET)" \n\t" -+ " nop \n\t" -+ " bclr "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_RESET)" \n\t" -+ " pipe_flush 0 \n\t" -+ : -+ : "a"(cc) -+ : "cc" -+ ); -+ -+ if (cc == DCCR_BASE) -+ UBICOM32_UNLOCK(DCCR_LOCK_BIT); -+ else -+ UBICOM32_UNLOCK(ICCR_LOCK_BIT); -+ -+} -+ -+static inline void __flush_cache_all(void) -+{ -+ /* -+ * Flush Icache -+ */ -+ mem_cache_invalidate_all(ICCR_BASE); -+ -+ /* -+ * Flush Dcache -+ */ -+ mem_cache_invalidate_all(DCCR_BASE); -+} -+ -+#endif /* _ASM_UBICOM32_CACHEFLUSH_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/cache.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cache.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/cache.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cache.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,40 @@ -+/* -+ * arch/ubicom32/include/asm/cache.h -+ * Cache line definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_CACHE_H -+#define _ASM_UBICOM32_CACHE_H -+ -+/* -+ * bytes per L1 cache line -+ */ -+#define L1_CACHE_SHIFT 5 -+#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -+ -+#define __cacheline_aligned -+#define ____cacheline_aligned -+ -+#endif /* _ASM_UBICOM32_CACHE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/checksum.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/checksum.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/checksum.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/checksum.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,149 @@ -+/* -+ * arch/ubicom32/include/asm/checksum.h -+ * Checksum utilities for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_CHECKSUM_H -+#define _ASM_UBICOM32_CHECKSUM_H -+ -+#include -+ -+/* -+ * computes the checksum of a memory block at buff, length len, -+ * and adds in "sum" (32-bit) -+ * -+ * returns a 32-bit number suitable for feeding into itself -+ * or csum_tcpudp_magic -+ * -+ * this function must be called with even lengths, except -+ * for the last fragment, which may be odd -+ * -+ * it's best to have buff aligned on a 32-bit boundary -+ */ -+__wsum csum_partial(const void *buff, int len, __wsum sum); -+ -+/* -+ * the same as csum_partial, but copies from src while it -+ * checksums -+ * -+ * here even more important to align src and dst on a 32-bit (or even -+ * better 64-bit) boundary -+ */ -+ -+__wsum csum_partial_copy_nocheck(const void *src, void *dst, -+ int len, __wsum sum); -+ -+ -+/* -+ * the same as csum_partial_copy, but copies from user space. -+ * -+ * here even more important to align src and dst on a 32-bit (or even -+ * better 64-bit) boundary -+ */ -+ -+extern __wsum csum_partial_copy_from_user(const void __user *src, -+ void *dst, int len, __wsum sum, int *csum_err); -+ -+__sum16 ip_fast_csum(const void *iph, unsigned int ihl); -+ -+/* -+ * Fold a partial checksum -+ */ -+ -+static inline __sum16 csum_fold(__wsum sum) -+{ -+ asm volatile ( -+ " lsr.4 d15, %0, #16 \n\t" -+ " bfextu %0, %0, #16 \n\t" -+ " add.4 %0, d15, %0 \n\t" -+ " lsr.4 d15, %0, #16 \n\t" -+ " bfextu %0, %0, #16 \n\t" -+ " add.4 %0, d15, %0 \n\t" -+ : "=&d" (sum) -+ : "0"(sum) -+ : "d15" -+ ); -+ return (__force __sum16)~sum; -+} -+ -+ -+/* -+ * computes the checksum of the TCP/UDP pseudo-header -+ * returns a 16-bit checksum, already complemented -+ */ -+ -+static inline __wsum -+csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, -+ unsigned short proto, __wsum sum) -+{ -+ asm volatile ( -+ " add.4 %0, %2, %0 \n\t" -+ " addc %0, %3, %0 \n\t" -+ " addc %0, %4, %0 \n\t" -+ " addc %0, %5, %0 \n\t" -+ " addc %0, #0, %0 \n\t" -+ : "=&d" (sum) -+ : "0"(sum), "r" (saddr), "r" (daddr), "r" (len), "r"(proto) -+ ); -+ return sum; -+} -+ -+static inline __sum16 -+csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len, -+ unsigned short proto, __wsum sum) -+{ -+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); -+} -+ -+/* -+ * this routine is used for miscellaneous IP-like checksums, mainly -+ * in icmp.c -+ */ -+extern __sum16 ip_compute_csum(const void *buff, int len); -+ -+#define _HAVE_ARCH_IPV6_CSUM -+ -+static __inline__ __sum16 -+csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr, -+ __u32 len, unsigned short proto, __wsum sum) -+{ -+ asm volatile ( -+ " add.4 %0, 0(%2), %0 \n\t" -+ " addc %0, 4(%2), %0 \n\t" -+ " addc %0, 8(%2), %0 \n\t" -+ " addc %0, 12(%2), %0 \n\t" -+ " addc %0, 0(%3), %0 \n\t" -+ " addc %0, 4(%3), %0 \n\t" -+ " addc %0, 8(%3), %0 \n\t" -+ " addc %0, 12(%3), %0 \n\t" -+ " addc %0, %4, %0 \n\t" -+ " addc %0, #0, %0 \n\t" -+ : "=&d" (sum) -+ : "0" (sum), "a" (saddr), "a" (daddr), "d" (len + proto) -+ ); -+ return csum_fold(sum); -+} -+ -+#endif /* _ASM_UBICOM32_CHECKSUM_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/cpu.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cpu.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/cpu.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cpu.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,45 @@ -+/* -+ * arch/ubicom32/include/asm/cpu.h -+ * CPU definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2004-2005 ARM Ltd. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_CPU_H -+#define _ASM_UBICOM32_CPU_H -+ -+#include -+ -+struct cpuinfo_ubicom32 { -+ unsigned long tid; /* Hardware thread number */ -+ -+#ifdef CONFIG_SMP -+ volatile unsigned long ipi_pending; /* Bit map of operations to execute */ -+ unsigned long ipi_count; /* Number of IPI(s) taken on this cpu */ -+#endif -+}; -+ -+DECLARE_PER_CPU(struct cpuinfo_ubicom32, cpu_data); -+ -+#endif /* _ASM_UBICOM32_CPU_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/cputime.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cputime.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/cputime.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/cputime.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/cputime.h -+ * Generic cputime.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_CPUTIME_H -+#define _ASM_UBICOM32_CPUTIME_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_CPUTIME_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/current.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/current.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/current.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/current.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,44 @@ -+/* -+ * arch/ubicom32/include/asm/current.h -+ * Definition of get_current() for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * (C) Copyright 2000, Lineo, David McCullough -+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_CURRENT_H -+#define _ASM_UBICOM32_CURRENT_H -+ -+#include -+ -+struct task_struct; -+ -+static inline struct task_struct *get_current(void) -+{ -+ return(current_thread_info()->task); -+} -+ -+#define current get_current() -+ -+#endif /* _ASM_UBICOM32_CURRENT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/delay.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/delay.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/delay.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/delay.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,75 @@ -+/* -+ * arch/ubicom32/include/asm/delay.h -+ * Definition of delay routines for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_DELAY_H -+#define _ASM_UBICOM32_DELAY_H -+ -+#include -+#include -+ -+static inline void __delay(unsigned long loops) -+{ -+ if (loops == 0) { -+ return; -+ } -+ -+ asm volatile ( -+ "1: add.4 %0, #-1, %0 \n\t" -+ " jmpne.t 1b \n\t" -+ : "+d" (loops) -+ ); -+} -+ -+/* -+ * Ubicom32 processor uses fixed 12MHz external OSC. -+ * So we use that as reference to count 12 cycles/us -+ */ -+ -+extern unsigned long loops_per_jiffy; -+ -+static inline void _udelay(unsigned long usecs) -+{ -+#if defined(CONFIG_UBICOM32_V4) || defined(CONFIG_UBICOM32_V3) -+ asm volatile ( -+ " add.4 d15, 0(%0), %1 \n\t" -+ " sub.4 #0, 0(%0), d15 \n\t" -+ " jmpmi.w.f .-4 \n\t" -+ : -+ : "a"(TIMER_BASE + TIMER_MPTVAL), "d"(usecs * (12000000/1000000)) -+ : "d15" -+ ); -+#else -+ BUG(); -+#endif -+} -+ -+/* -+ * Moved the udelay() function into library code, no longer inlined. -+ */ -+extern void udelay(unsigned long usecs); -+ -+#endif /* _ASM_UBICOM32_DELAY_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/device.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/device.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/device.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/device.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,35 @@ -+/* -+ * arch/ubicom32/include/asm/device.h -+ * Generic device.h for Ubicom32 architecture. -+ * -+ * Used for arch specific extensions to struct device -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_DEVICE_H -+#define _ASM_UBICOM32_DEVICE_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_DEVICE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/devtree.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/devtree.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/devtree.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/devtree.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,52 @@ -+/* -+ * arch/ubicom32/include/asm/devtree.h -+ * Device Tree Header File (Shared between ultra and the Host OS) -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_DEVTREE_H -+#define _ASM_UBICOM32_DEVTREE_H -+ -+#define DEVTREE_MAX_NAME 32 -+#define DEVTREE_IRQ_NONE 0xff -+#define DEVTREE_IRQ_DONTCARE 0xff -+#define DEVTREE_NODE_MAGIC 0x10203040 -+ -+struct devtree_node { -+ struct devtree_node *next; -+ unsigned char sendirq; -+ unsigned char recvirq; -+ char name[DEVTREE_MAX_NAME]; -+ unsigned int magic; -+}; -+ -+extern struct devtree_node *devtree; -+extern struct devtree_node *devtree_find_by_irq(uint8_t sendirq, uint8_t recvirq); -+extern struct devtree_node *devtree_find_node(const char *str); -+extern struct devtree_node *devtree_find_next(struct devtree_node **cur); -+extern int devtree_irq(struct devtree_node *dn, unsigned char *sendirq, unsigned char *recvirq); -+extern void devtree_print(void); -+ -+#endif /* _ASM_UBICOM32_DEVTREE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/div64.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/div64.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/div64.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/div64.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/div64.h -+ * Generic div64.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_DIV64_H -+#define _ASM_UBICOM32_DIV64_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_DIV64_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/dma.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/dma.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/dma.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/dma.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,34 @@ -+/* -+ * arch/ubicom32/include/asm/dma.h -+ * DMA definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_DMA_H -+#define _ASM_UBICOM32_DMA_H -+ -+/* Nothing so far */ -+#define MAX_DMA_ADDRESS 0x00 /* This is quite suspicious */ -+ -+#endif /* _ASM_UBICOM32_DMA_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/dma-mapping.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/dma-mapping.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/dma-mapping.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/dma-mapping.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,328 @@ -+/* -+ * arch/ubicom32/include/asm/dma-mapping.h -+ * Generic dma-mapping.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_DMA_MAPPING_H -+#define _ASM_UBICOM32_DMA_MAPPING_H -+ -+#include -+#ifdef CONFIG_PCI -+ -+/* we implement the API below in terms of the existing PCI one, -+ * so include it */ -+#include -+/* need struct page definitions */ -+#include -+ -+static inline int -+dma_supported(struct device *dev, u64 mask) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ return pci_dma_supported(to_pci_dev(dev), mask); -+} -+ -+static inline int -+dma_set_mask(struct device *dev, u64 dma_mask) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ return pci_set_dma_mask(to_pci_dev(dev), dma_mask); -+} -+ -+static inline void * -+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, -+ gfp_t flag) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); -+} -+ -+static inline void -+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, -+ dma_addr_t dma_handle) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); -+} -+ -+static inline dma_addr_t -+dma_map_single(struct device *dev, void *cpu_addr, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); -+} -+ -+static inline void -+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); -+} -+ -+static inline dma_addr_t -+dma_map_page(struct device *dev, struct page *page, -+ unsigned long offset, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); -+} -+ -+static inline void -+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); -+} -+ -+static inline int -+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); -+} -+ -+static inline void -+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); -+} -+ -+static inline void -+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, -+ size, (int)direction); -+} -+ -+static inline void -+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, -+ size, (int)direction); -+} -+ -+static inline void -+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); -+} -+ -+static inline void -+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, -+ enum dma_data_direction direction) -+{ -+ BUG_ON(dev->bus != &pci_bus_type); -+ -+ pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); -+} -+ -+static inline int -+dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -+{ -+ return pci_dma_mapping_error(to_pci_dev(dev), dma_addr); -+} -+ -+ -+#else -+ -+static inline int -+dma_supported(struct device *dev, u64 mask) -+{ -+ return 0; -+} -+ -+static inline int -+dma_set_mask(struct device *dev, u64 dma_mask) -+{ -+ BUG(); -+ return 0; -+} -+ -+static inline void * -+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, -+ gfp_t flag) -+{ -+ BUG(); -+ return NULL; -+} -+ -+static inline void -+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, -+ dma_addr_t dma_handle) -+{ -+ BUG(); -+} -+ -+static inline dma_addr_t -+dma_map_single(struct device *dev, void *cpu_addr, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+ return 0; -+} -+ -+static inline void -+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+} -+ -+static inline dma_addr_t -+dma_map_page(struct device *dev, struct page *page, -+ unsigned long offset, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+ return 0; -+} -+ -+static inline void -+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+} -+ -+static inline int -+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+ return 0; -+} -+ -+static inline void -+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+} -+ -+static inline void -+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+} -+ -+static inline void -+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+} -+ -+static inline void -+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+} -+ -+static inline void -+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, -+ enum dma_data_direction direction) -+{ -+ BUG(); -+} -+ -+static inline int -+dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -+{ -+ return 0; -+} -+ -+#endif -+ -+/* Now for the API extensions over the pci_ one */ -+ -+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -+#define dma_is_consistent(d, h) (1) -+ -+static inline int -+dma_get_cache_alignment(void) -+{ -+ /* no easy way to get cache size on all processors, so return -+ * the maximum possible, to be safe */ -+ return (1 << INTERNODE_CACHE_SHIFT); -+} -+ -+static inline void -+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, -+ unsigned long offset, size_t size, -+ enum dma_data_direction direction) -+{ -+ /* just sync everything, that's all the pci API can do */ -+ dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction); -+} -+ -+static inline void -+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, -+ unsigned long offset, size_t size, -+ enum dma_data_direction direction) -+{ -+ /* just sync everything, that's all the pci API can do */ -+ dma_sync_single_for_device(dev, dma_handle, offset+size, direction); -+} -+ -+static inline void -+dma_cache_sync(struct device *dev, void *vaddr, size_t size, -+ enum dma_data_direction direction) -+{ -+ /* could define this in terms of the dma_cache ... operations, -+ * but if you get this on a platform, you should convert the platform -+ * to using the generic device DMA API */ -+ BUG(); -+} -+ -+#endif /* _ASM_UBICOM32_DMA_MAPPING_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/elf.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/elf.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/elf.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/elf.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,173 @@ -+/* -+ * arch/ubicom32/include/asm/elf.h -+ * Definitions for elf executable format for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_ELF_H -+#define _ASM_UBICOM32_ELF_H -+ -+/* -+ * ELF register definitions.. -+ */ -+ -+#include -+#include -+ -+/* -+ * Processor specific flags for the ELF header e_flags field. -+ */ -+#define EF_UBICOM32_V3 0x00000001 /* -fmarch=ubicom32v3 */ -+#define EF_UBICOM32_V4 0x00000002 /* -fmarch=ubicom32v4 */ -+#define EF_UBICOM32_PIC 0x80000000 /* -fpic */ -+#define EF_UBICOM32_FDPIC 0x40000000 /* -mfdpic */ -+ -+/* -+ * Ubicom32 ELF relocation types -+ */ -+#define R_UBICOM32_NONE 0 -+#define R_UBICOM32_16 1 -+#define R_UBICOM32_32 2 -+#define R_UBICOM32_LO16 3 -+#define R_UBICOM32_HI16 4 -+#define R_UBICOM32_21_PCREL 5 -+#define R_UBICOM32_24_PCREL 6 -+#define R_UBICOM32_HI24 7 -+#define R_UBICOM32_LO7_S 8 -+#define R_UBICOM32_LO7_2_S 9 -+#define R_UBICOM32_LO7_4_S 10 -+#define R_UBICOM32_LO7_D 11 -+#define R_UBICOM32_LO7_2_D 12 -+#define R_UBICOM32_LO7_4_D 13 -+#define R_UBICOM32_32_HARVARD 14 -+#define R_UBICOM32_LO7_CALLI 15 -+#define R_UBICOM32_LO16_CALLI 16 -+#define R_UBICOM32_GOT_HI24 17 -+#define R_UBICOM32_GOT_LO7_S 18 -+#define R_UBICOM32_GOT_LO7_2_S 19 -+#define R_UBICOM32_GOT_LO7_4_S 20 -+#define R_UBICOM32_GOT_LO7_D 21 -+#define R_UBICOM32_GOT_LO7_2_D 22 -+#define R_UBICOM32_GOT_LO7_4_D 23 -+#define R_UBICOM32_FUNCDESC_GOT_HI24 24 -+#define R_UBICOM32_FUNCDESC_GOT_LO7_S 25 -+#define R_UBICOM32_FUNCDESC_GOT_LO7_2_S 26 -+#define R_UBICOM32_FUNCDESC_GOT_LO7_4_S 27 -+#define R_UBICOM32_FUNCDESC_GOT_LO7_D 28 -+#define R_UBICOM32_FUNCDESC_GOT_LO7_2_D 29 -+#define R_UBICOM32_FUNCDESC_GOT_LO7_4_D 30 -+#define R_UBICOM32_GOT_LO7_CALLI 31 -+#define R_UBICOM32_FUNCDESC_GOT_LO7_CALLI 32 -+#define R_UBICOM32_FUNCDESC_VALUE 33 -+#define R_UBICOM32_FUNCDESC 34 -+#define R_UBICOM32_GOTOFFSET_LO 35 -+#define R_UBICOM32_GOTOFFSET_HI 36 -+#define R_UBICOM32_FUNCDESC_GOTOFFSET_LO 37 -+#define R_UBICOM32_FUNCDESC_GOTOFFSET_HI 38 -+#define R_UBICOM32_GNU_VTINHERIT 200 -+#define R_UBICOM32_GNU_VTENTRY 201 -+ -+typedef unsigned long elf_greg_t; -+ -+#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t)) -+typedef elf_greg_t elf_gregset_t[ELF_NGREG]; -+ -+typedef struct user_ubicom32fp_struct elf_fpregset_t; -+ -+/* -+ * This is used to ensure we don't load something for the wrong architecture. -+ */ -+#define elf_check_arch(x) ((x)->e_machine == EM_UBICOM32) -+ -+#define elf_check_fdpic(x) ((x)->e_flags & EF_UBICOM32_FDPIC) -+ -+#define elf_check_const_displacement(x) ((x)->e_flags & EF_UBICOM32_PIC) -+ -+/* -+ * These are used to set parameters in the core dumps. -+ */ -+#define ELF_CLASS ELFCLASS32 -+#define ELF_DATA ELFDATA2MSB -+#define ELF_ARCH EM_UBICOM32 -+ -+/* For SVR4/m68k the function pointer to be registered with `atexit' is -+ passed in %a1. Although my copy of the ABI has no such statement, it -+ is actually used on ASV. */ -+#define ELF_PLAT_INIT(_r, load_addr) _r->a1 = 0 -+ -+#define ELF_FDPIC_PLAT_INIT(_regs, _exec_map_addr, _interp_map_addr, \ -+ _dynamic_addr) \ -+ do { \ -+ _regs->dn[1] = _exec_map_addr; \ -+ _regs->dn[2] = _interp_map_addr; \ -+ _regs->dn[3] = _dynamic_addr; \ -+ _regs->an[1] = 0; /* dl_fini will be set by ldso */ \ -+ } while (0) -+ -+#define USE_ELF_CORE_DUMP -+#define ELF_EXEC_PAGESIZE 4096 -+ -+#ifdef __KERNEL__ -+#ifdef CONFIG_UBICOM32_V4 -+#define ELF_FDPIC_CORE_EFLAGS (EF_UBICOM32_FDPIC | EF_UBICOM32_V4) -+#elif defined CONFIG_UBICOM32_V3 -+#define ELF_FDPIC_CORE_EFLAGS (EF_UBICOM32_FDPIC | EF_UBICOM32_V3) -+#else -+#error Unknown/Unsupported ubicom32 architecture. -+#endif -+#endif -+ -+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical -+ use of this is to invoke "./ld.so someprog" to test out a new version of -+ the loader. We need to make sure that it is out of the way of the program -+ that it will "exec", and that there is sufficient room for the brk. */ -+ -+#define ELF_ET_DYN_BASE 0xD0000000UL -+ -+/* -+ * For Ubicom32, the elf_gregset_t and struct pt_regs are the same size -+ * data structure so a copy is performed instead of providing the -+ * ELF_CORE_COPY_REGS macro. -+ */ -+ -+/* -+ * ELF_CORE_COPY_TASK_REGS is needed to dump register state from multi threaded user projects. -+ */ -+extern int dump_task_regs(struct task_struct *, elf_gregset_t *); -+#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs) -+ -+/* This yields a mask that user programs can use to figure out what -+ instruction set this cpu supports. */ -+ -+#define ELF_HWCAP (0) -+ -+/* This yields a string that ld.so will use to load implementation -+ specific libraries for optimization. This is more specific in -+ intent than poking at uname or /proc/cpuinfo. */ -+ -+#define ELF_PLATFORM (NULL) -+ -+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) -+ -+#endif /* _ASM_UBICOM32_ELF_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/emergency-restart.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/emergency-restart.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/emergency-restart.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/emergency-restart.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/emergency-restart.h -+ * Generic emergency-restart.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_EMERGENCY_RESTART_H -+#define _ASM_UBICOM32_EMERGENCY_RESTART_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_EMERGENCY_RESTART_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/entry.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/entry.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/entry.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/entry.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,34 @@ -+/* -+ * arch/ubicom32/include/asm/entry.h -+ * Entry register/stack definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_ENTRY_H -+#define _ASM_UBICOM32_ENTRY_H -+ -+#include -+#include -+ -+#endif /* _ASM_UBICOM32_ENTRY_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/errno.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/errno.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/errno.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/errno.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/errno.h -+ * Generic errno.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_ERRNO_H -+#define _ASM_UBICOM32_ERRNO_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_ERRNO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/fb.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/fb.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/fb.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/fb.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,39 @@ -+/* -+ * arch/ubicom32/include/asm/fb.h -+ * Definition of fb_is_primary_device() for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_FB_H -+#define _ASM_UBICOM32_FB_H -+#include -+ -+#define fb_pgprotect(...) do {} while (0) -+ -+static inline int fb_is_primary_device(struct fb_info *info) -+{ -+ return 0; -+} -+ -+#endif /* _ASM_UBICOM32_FB_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/fcntl.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/fcntl.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/fcntl.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/fcntl.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,38 @@ -+/* -+ * arch/ubicom32/include/asm/fcntl.h -+ * File control bit definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_FCNTL_H -+#define _ASM_UBICOM32_FCNTL_H -+ -+#define O_DIRECTORY 040000 /* must be a directory */ -+#define O_NOFOLLOW 0100000 /* don't follow links */ -+#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ -+#define O_LARGEFILE 0400000 -+ -+#include -+ -+#endif /* _ASM_UBICOM32_FCNTL_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/flat.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/flat.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/flat.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/flat.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,73 @@ -+/* -+ * arch/ubicom32/include/asm/flat.h -+ * Definitions to support flat-format executables. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_FLAT_H -+#define _ASM_UBICOM32_FLAT_H -+ -+#define ARCH_FLAT_ALIGN 0x80 -+#define ARCH_FLAT_ALIGN_TEXT 1 -+ -+#define R_UBICOM32_32 2 -+#define R_UBICOM32_HI24 7 -+#define R_UBICOM32_LO7_S 8 -+#define R_UBICOM32_LO7_2_S 9 -+#define R_UBICOM32_LO7_4_S 10 -+#define R_UBICOM32_LO7_D 11 -+#define R_UBICOM32_LO7_2_D 12 -+#define R_UBICOM32_LO7_4_D 13 -+#define R_UBICOM32_LO7_CALLI 15 -+#define R_UBICOM32_LO16_CALLI 16 -+ -+extern void ubicom32_flat_put_addr_at_rp(unsigned long *rp, u32_t val, u32_t rval, unsigned long *p); -+extern unsigned long ubicom32_flat_get_addr_from_rp(unsigned long *rp, u32_t relval, u32_t flags, unsigned long *p); -+ -+#define flat_stack_align(sp) /* nothing needed */ -+#define flat_argvp_envp_on_stack() 1 -+#define flat_old_ram_flag(flags) (flags) -+#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) -+#define flat_get_addr_from_rp(rp, relval, flags, p) (ubicom32_flat_get_addr_from_rp(rp, relval,flags, p)) -+#define flat_put_addr_at_rp(rp, val, relval) do {ubicom32_flat_put_addr_at_rp(rp, val, relval, &persistent);} while(0) -+#define flat_get_relocate_addr(rel) ((persistent) ? (persistent & 0x07ffffff) : (rel & 0x07ffffff)) -+ -+static inline int flat_set_persistent(unsigned int relval, unsigned long *p) -+{ -+ if (*p) { -+ return 0; -+ } else { -+ if ((relval >> 27) != R_UBICOM32_32) { -+ /* -+ * Something other than UBICOM32_32. The next entry has the relocation. -+ */ -+ *p = relval; -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+#endif /* _ASM_UBICOM32_FLAT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/fpu.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/fpu.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/fpu.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/fpu.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,37 @@ -+/* -+ * arch/ubicom32/include/asm/fpu.h -+ * Floating point state definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_FPU_H -+#define _ASM_UBICOM32_FPU_H -+ -+/* -+ * MAX floating point unit state size (FSAVE/FRESTORE) -+ */ -+/* No FP unit present then... */ -+#define FPSTATESIZE (2) /* dummy size */ -+ -+#endif /* _ASM_UBICOM32_FPU_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ftrace.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ftrace.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ftrace.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ftrace.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1 @@ -+/* empty */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/futex.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/futex.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/futex.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/futex.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/futex.h -+ * Generic futex.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_FUTEX_H -+#define _ASM_UBICOM32_FUTEX_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_FUTEX_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/.gitignore linux-2.6.30.10-ubi/arch/ubicom32/include/asm/.gitignore ---- linux-2.6.30.10/arch/ubicom32/include/asm/.gitignore 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/.gitignore 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1 @@ -+/ocm_size.h -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/gpio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/gpio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/gpio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/gpio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,453 @@ -+/* -+ * arch/ubicom32/include/asm/gpio.h -+ * Definitions for GPIO operations on Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_GPIO_H -+#define _ASM_UBICOM32_GPIO_H -+ -+#include -+#include -+ -+#include -+ -+#define ARCH_NR_GPIOS 512 -+#define MAX_UBICOM_ONCHIP_GPIO (9 * 32) -+ -+/* -+ * Macros for manipulating GPIO numbers -+ */ -+#define gpio_bit(gn) (1 << (gn & 0x1f)) -+#define gpio_bank(gn) (gn >> 5) -+ -+#define gpio_pin_index(gn) (gn & 0x1f) -+#define gpio_port_index(gn) (gn >> 5) -+ -+#define GPIO_RA_0 ((32 * 0) + 0) -+#define GPIO_RA_1 ((32 * 0) + 1) -+#define GPIO_RA_2 ((32 * 0) + 2) -+#define GPIO_RA_3 ((32 * 0) + 3) -+#define GPIO_RA_4 ((32 * 0) + 4) -+#define GPIO_RA_5 ((32 * 0) + 5) -+#define GPIO_RA_6 ((32 * 0) + 6) -+#define GPIO_RA_7 ((32 * 0) + 7) -+ -+#define GPIO_RB_0 ((32 * 1) + 0) -+#define GPIO_RB_1 ((32 * 1) + 1) -+#define GPIO_RB_2 ((32 * 1) + 2) -+#define GPIO_RB_3 ((32 * 1) + 3) -+#define GPIO_RB_4 ((32 * 1) + 4) -+#define GPIO_RB_5 ((32 * 1) + 5) -+#define GPIO_RB_6 ((32 * 1) + 6) -+#define GPIO_RB_7 ((32 * 1) + 7) -+#define GPIO_RB_8 ((32 * 1) + 8) -+#define GPIO_RB_9 ((32 * 1) + 9) -+#define GPIO_RB_10 ((32 * 1) + 10) -+#define GPIO_RB_11 ((32 * 1) + 11) -+#define GPIO_RB_12 ((32 * 1) + 12) -+#define GPIO_RB_13 ((32 * 1) + 13) -+#define GPIO_RB_14 ((32 * 1) + 14) -+#define GPIO_RB_15 ((32 * 1) + 15) -+#define GPIO_RB_16 ((32 * 1) + 16) -+#define GPIO_RB_17 ((32 * 1) + 17) -+#define GPIO_RB_18 ((32 * 1) + 18) -+#define GPIO_RB_19 ((32 * 1) + 19) -+ -+#define GPIO_RC_0 ((32 * 2) + 0) -+#define GPIO_RC_1 ((32 * 2) + 1) -+#define GPIO_RC_2 ((32 * 2) + 2) -+#define GPIO_RC_3 ((32 * 2) + 3) -+#define GPIO_RC_4 ((32 * 2) + 4) -+#define GPIO_RC_5 ((32 * 2) + 5) -+#define GPIO_RC_6 ((32 * 2) + 6) -+#define GPIO_RC_7 ((32 * 2) + 7) -+#define GPIO_RC_8 ((32 * 2) + 8) -+#define GPIO_RC_9 ((32 * 2) + 9) -+#define GPIO_RC_10 ((32 * 2) + 10) -+#define GPIO_RC_11 ((32 * 2) + 11) -+#define GPIO_RC_12 ((32 * 2) + 12) -+#define GPIO_RC_13 ((32 * 2) + 13) -+#define GPIO_RC_14 ((32 * 2) + 14) -+#define GPIO_RC_15 ((32 * 2) + 15) -+#define GPIO_RC_16 ((32 * 2) + 16) -+#define GPIO_RC_17 ((32 * 2) + 17) -+#define GPIO_RC_18 ((32 * 2) + 18) -+#define GPIO_RC_19 ((32 * 2) + 19) -+#define GPIO_RC_20 ((32 * 2) + 20) -+#define GPIO_RC_21 ((32 * 2) + 21) -+#define GPIO_RC_22 ((32 * 2) + 22) -+#define GPIO_RC_23 ((32 * 2) + 23) -+#define GPIO_RC_24 ((32 * 2) + 24) -+#define GPIO_RC_25 ((32 * 2) + 25) -+#define GPIO_RC_26 ((32 * 2) + 26) -+#define GPIO_RC_27 ((32 * 2) + 27) -+#define GPIO_RC_28 ((32 * 2) + 28) -+#define GPIO_RC_29 ((32 * 2) + 29) -+#define GPIO_RC_30 ((32 * 2) + 30) -+#define GPIO_RC_31 ((32 * 2) + 31) -+ -+#define GPIO_RD_0 ((32 * 3) + 0) -+#define GPIO_RD_1 ((32 * 3) + 1) -+#define GPIO_RD_2 ((32 * 3) + 2) -+#define GPIO_RD_3 ((32 * 3) + 3) -+#define GPIO_RD_4 ((32 * 3) + 4) -+#define GPIO_RD_5 ((32 * 3) + 5) -+#define GPIO_RD_6 ((32 * 3) + 6) -+#define GPIO_RD_7 ((32 * 3) + 7) -+#define GPIO_RD_8 ((32 * 3) + 8) -+#define GPIO_RD_9 ((32 * 3) + 9) -+#define GPIO_RD_10 ((32 * 3) + 10) -+#define GPIO_RD_11 ((32 * 3) + 11) -+ -+#define GPIO_RE_0 ((32 * 4) + 0) -+#define GPIO_RE_1 ((32 * 4) + 1) -+#define GPIO_RE_2 ((32 * 4) + 2) -+#define GPIO_RE_3 ((32 * 4) + 3) -+#define GPIO_RE_4 ((32 * 4) + 4) -+#define GPIO_RE_5 ((32 * 4) + 5) -+#define GPIO_RE_6 ((32 * 4) + 6) -+#define GPIO_RE_7 ((32 * 4) + 7) -+ -+#define GPIO_RF_0 ((32 * 5) + 0) -+#define GPIO_RF_1 ((32 * 5) + 1) -+#define GPIO_RF_2 ((32 * 5) + 2) -+#define GPIO_RF_3 ((32 * 5) + 3) -+#define GPIO_RF_4 ((32 * 5) + 4) -+#define GPIO_RF_5 ((32 * 5) + 5) -+#define GPIO_RF_6 ((32 * 5) + 6) -+#define GPIO_RF_7 ((32 * 5) + 7) -+#define GPIO_RF_8 ((32 * 5) + 8) -+#define GPIO_RF_9 ((32 * 5) + 9) -+#define GPIO_RF_10 ((32 * 5) + 10) -+#define GPIO_RF_11 ((32 * 5) + 11) -+#define GPIO_RF_12 ((32 * 5) + 12) -+#define GPIO_RF_13 ((32 * 5) + 13) -+#define GPIO_RF_14 ((32 * 5) + 14) -+#define GPIO_RF_15 ((32 * 5) + 15) -+ -+#define GPIO_RG_0 ((32 * 6) + 0) -+#define GPIO_RG_1 ((32 * 6) + 1) -+#define GPIO_RG_2 ((32 * 6) + 2) -+#define GPIO_RG_3 ((32 * 6) + 3) -+#define GPIO_RG_4 ((32 * 6) + 4) -+#define GPIO_RG_5 ((32 * 6) + 5) -+#define GPIO_RG_6 ((32 * 6) + 6) -+#define GPIO_RG_7 ((32 * 6) + 7) -+#define GPIO_RG_8 ((32 * 6) + 8) -+#define GPIO_RG_9 ((32 * 6) + 9) -+#define GPIO_RG_10 ((32 * 6) + 10) -+#define GPIO_RG_11 ((32 * 6) + 11) -+#define GPIO_RG_12 ((32 * 6) + 12) -+#define GPIO_RG_13 ((32 * 6) + 13) -+#define GPIO_RG_14 ((32 * 6) + 14) -+#define GPIO_RG_15 ((32 * 6) + 15) -+#define GPIO_RG_16 ((32 * 6) + 16) -+#define GPIO_RG_17 ((32 * 6) + 17) -+#define GPIO_RG_18 ((32 * 6) + 18) -+#define GPIO_RG_19 ((32 * 6) + 19) -+#define GPIO_RG_20 ((32 * 6) + 20) -+#define GPIO_RG_21 ((32 * 6) + 21) -+#define GPIO_RG_22 ((32 * 6) + 22) -+#define GPIO_RG_23 ((32 * 6) + 23) -+#define GPIO_RG_24 ((32 * 6) + 24) -+#define GPIO_RG_25 ((32 * 6) + 25) -+#define GPIO_RG_26 ((32 * 6) + 26) -+#define GPIO_RG_27 ((32 * 6) + 27) -+#define GPIO_RG_28 ((32 * 6) + 28) -+#define GPIO_RG_29 ((32 * 6) + 29) -+#define GPIO_RG_30 ((32 * 6) + 30) -+#define GPIO_RG_31 ((32 * 6) + 31) -+ -+#define GPIO_RH_0 ((32 * 7) + 0) -+#define GPIO_RH_1 ((32 * 7) + 1) -+#define GPIO_RH_2 ((32 * 7) + 2) -+#define GPIO_RH_3 ((32 * 7) + 3) -+#define GPIO_RH_4 ((32 * 7) + 4) -+#define GPIO_RH_5 ((32 * 7) + 5) -+#define GPIO_RH_6 ((32 * 7) + 6) -+#define GPIO_RH_7 ((32 * 7) + 7) -+#define GPIO_RH_8 ((32 * 7) + 8) -+#define GPIO_RH_9 ((32 * 7) + 9) -+ -+#define GPIO_RI_0 ((32 * 8) + 0) -+#define GPIO_RI_1 ((32 * 8) + 1) -+#define GPIO_RI_2 ((32 * 8) + 2) -+#define GPIO_RI_3 ((32 * 8) + 3) -+#define GPIO_RI_4 ((32 * 8) + 4) -+#define GPIO_RI_5 ((32 * 8) + 5) -+#define GPIO_RI_6 ((32 * 8) + 6) -+#define GPIO_RI_7 ((32 * 8) + 7) -+#define GPIO_RI_8 ((32 * 8) + 8) -+#define GPIO_RI_9 ((32 * 8) + 9) -+#define GPIO_RI_10 ((32 * 8) + 10) -+#define GPIO_RI_11 ((32 * 8) + 11) -+#define GPIO_RI_12 ((32 * 8) + 12) -+#define GPIO_RI_13 ((32 * 8) + 13) -+#define GPIO_RI_14 ((32 * 8) + 14) -+#define GPIO_RI_15 ((32 * 8) + 15) -+ -+/* -+ * The following section defines extra GPIO available to some boards. -+ * These GPIO are generally external to the processor (i.e. SPI/I2C -+ * expander chips). -+ * -+ * Note that these defines show all possible GPIO available, however, -+ * depending on the actual board configuration, some GPIO are not -+ * available for use. -+ */ -+#ifdef CONFIG_IP7500MEDIA -+/* -+ * U15 -+ */ -+#define IP7500MEDIA_U15_BASE (32 * 10) -+#define IP7500MEDIA_IO0 (IP7500MEDIA_U15_BASE + 0) -+#define IP7500MEDIA_IO1 (IP7500MEDIA_U15_BASE + 1) -+#define IP7500MEDIA_IO2 (IP7500MEDIA_U15_BASE + 2) -+#define IP7500MEDIA_IO3 (IP7500MEDIA_U15_BASE + 3) -+#define IP7500MEDIA_IO4 (IP7500MEDIA_U15_BASE + 4) -+#define IP7500MEDIA_IO5 (IP7500MEDIA_U15_BASE + 5) -+#define IP7500MEDIA_IO6 (IP7500MEDIA_U15_BASE + 6) -+#define IP7500MEDIA_IO7 (IP7500MEDIA_U15_BASE + 7) -+ -+/* -+ * U16 -+ */ -+#define IP7500MEDIA_U16_BASE (32 * 11) -+#define IP7500MEDIA_IO8 (IP7500MEDIA_U16_BASE + 0) -+#define IP7500MEDIA_IO9 (IP7500MEDIA_U16_BASE + 1) -+#define IP7500MEDIA_IO10 (IP7500MEDIA_U16_BASE + 2) -+#define IP7500MEDIA_IO11 (IP7500MEDIA_U16_BASE + 3) -+#define IP7500MEDIA_IO12 (IP7500MEDIA_U16_BASE + 4) -+#define IP7500MEDIA_IO13 (IP7500MEDIA_U16_BASE + 5) -+#define IP7500MEDIA_IO14 (IP7500MEDIA_U16_BASE + 6) -+#define IP7500MEDIA_IO15 (IP7500MEDIA_U16_BASE + 7) -+ -+/* -+ * U17 -+ */ -+#define IP7500MEDIA_U17_BASE (32 * 12) -+#define IP7500MEDIA_IO16 (IP7500MEDIA_U17_BASE + 0) -+#define IP7500MEDIA_IO17 (IP7500MEDIA_U17_BASE + 1) -+#define IP7500MEDIA_IO18 (IP7500MEDIA_U17_BASE + 2) -+#define IP7500MEDIA_IO19 (IP7500MEDIA_U17_BASE + 3) -+#define IP7500MEDIA_IO20 (IP7500MEDIA_U17_BASE + 4) -+#define IP7500MEDIA_IO21 (IP7500MEDIA_U17_BASE + 5) -+#define IP7500MEDIA_IO22 (IP7500MEDIA_U17_BASE + 6) -+#define IP7500MEDIA_IO23 (IP7500MEDIA_U17_BASE + 7) -+ -+/* -+ * U18 -+ */ -+#define IP7500MEDIA_U18_BASE (32 * 13) -+#define IP7500MEDIA_IO24 (IP7500MEDIA_U18_BASE + 0) -+#define IP7500MEDIA_IO25 (IP7500MEDIA_U18_BASE + 1) -+#define IP7500MEDIA_IO26 (IP7500MEDIA_U18_BASE + 2) -+#define IP7500MEDIA_IO27 (IP7500MEDIA_U18_BASE + 3) -+#define IP7500MEDIA_IO28 (IP7500MEDIA_U18_BASE + 4) -+#define IP7500MEDIA_IO29 (IP7500MEDIA_U18_BASE + 5) -+#define IP7500MEDIA_IO30 (IP7500MEDIA_U18_BASE + 6) -+#define IP7500MEDIA_IO31 (IP7500MEDIA_U18_BASE + 7) -+#endif -+ -+#ifdef CONFIG_IP7145DPF -+/* -+ * U48 -+ */ -+#define IP7145DPF_U48_BASE (32 * 10) -+#define IP7145DPF_IO0 (IP7145DPF_U48_BASE + 0) -+#define IP7145DPF_IO1 (IP7145DPF_U48_BASE + 1) -+#define IP7145DPF_IO2 (IP7145DPF_U48_BASE + 2) -+#define IP7145DPF_IO3 (IP7145DPF_U48_BASE + 3) -+#define IP7145DPF_IO4 (IP7145DPF_U48_BASE + 4) -+#define IP7145DPF_IO5 (IP7145DPF_U48_BASE + 5) -+#define IP7145DPF_IO6 (IP7145DPF_U48_BASE + 6) -+#define IP7145DPF_IO7 (IP7145DPF_U48_BASE + 7) -+ -+/* -+ * U72 -+ */ -+#define IP7145DPF_U72_BASE (32 * 11) -+#define IP7145DPF_IOB0 (IP7145DPF_U72_BASE + 0) -+#define IP7145DPF_IOB1 (IP7145DPF_U72_BASE + 1) -+#define IP7145DPF_IOB2 (IP7145DPF_U72_BASE + 2) -+#define IP7145DPF_IOB3 (IP7145DPF_U72_BASE + 3) -+#define IP7145DPF_IOB4 (IP7145DPF_U72_BASE + 4) -+#define IP7145DPF_IOB5 (IP7145DPF_U72_BASE + 5) -+#define IP7145DPF_IOB6 (IP7145DPF_U72_BASE + 6) -+#define IP7145DPF_IOB7 (IP7145DPF_U72_BASE + 7) -+#endif -+ -+#include -+ -+/* -+ * The following macros bypass gpiolib to generate direct references -+ * to the port registers. These assume, minimally, that either -+ * gpio_direction_input() or gpio_direction_output() have already been -+ * called to setup the pin direction and to enable the pin function to -+ * be gpio. These macros generate the hardware port address based on -+ * the assumption that all ports are 32 bits wide (even though we know -+ * they are not). This is so we can efficiently turn pin numbers into -+ * port addresses without a lookup. -+ * -+ * These operations must be done in one instruction to prevent clobbering -+ * other thread's accesses to the same port. -+ */ -+#define UBICOM32_GPIO_ENABLE(pin) \ -+ do { \ -+ asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t" \ -+ : \ -+ : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_mask), \ -+ [mask] "d" (gpio_bit(pin)) \ -+ : "cc", "memory" \ -+ ); \ -+ } while (0); -+ -+#define UBICOM32_GPIO_DISABLE(pin) \ -+ do { \ -+ asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t" \ -+ : \ -+ : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_mask), \ -+ [mask] "d" (~gpio_bit(pin)) \ -+ : "cc", "memory" \ -+ ); \ -+ } while (0); -+ -+#define UBICOM32_GPIO_SET_PIN_INPUT(pin) \ -+ do { \ -+ asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t" \ -+ : \ -+ : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_ctl), \ -+ [mask] "d" (~gpio_bit(pin)) \ -+ : "cc", "memory" \ -+ ); \ -+ } while (0); -+ -+#define UBICOM32_GPIO_SET_PIN_OUTPUT(pin) \ -+ do { \ -+ asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t" \ -+ : \ -+ : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_ctl), \ -+ [mask] "d" (gpio_bit(pin)) \ -+ : "cc", "memory" \ -+ ); \ -+ } while (0); -+ -+#define UBICOM32_GPIO_SET_PIN_TOGGLE(pin) \ -+ do { \ -+ asm volatile ("xor.4 (%[port]), (%[port]), %[mask]\n\t" \ -+ : \ -+ : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out), \ -+ [mask] "d" (gpio_bit(pin)) \ -+ : "cc", "memory" \ -+ ); \ -+ } while (0); -+ -+#define UBICOM32_GPIO_SET_PIN_HIGH(pin) \ -+ do { \ -+ asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t" \ -+ : \ -+ : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out), \ -+ [mask] "d" (gpio_bit(pin)) \ -+ : "cc", "memory" \ -+ ); \ -+ } while (0); -+ -+#define UBICOM32_GPIO_SET_PIN_LOW(pin) \ -+ do { \ -+ asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t" \ -+ : \ -+ : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out), \ -+ [mask] "d" (~gpio_bit(pin)) \ -+ : "cc", "memory" \ -+ ); \ -+ } while (0); -+ -+#define UBICOM32_GPIO_SET_PIN(pin, val) \ -+ if ( val ) { \ -+ UBICOM32_GPIO_SET_PIN_HIGH(pin); \ -+ } else { \ -+ UBICOM32_GPIO_SET_PIN_LOW(pin); \ -+ } -+ -+#define UBICOM32_GPIO_GET_PIN(pin) \ -+ (0 != (UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_in \ -+ & gpio_bit(pin))) -+ -+ -+static inline int gpio_get_value(unsigned gpio) -+{ -+ if (gpio <= MAX_UBICOM_ONCHIP_GPIO) -+ return UBICOM32_GPIO_GET_PIN(gpio); -+ else -+ return __gpio_get_value(gpio); -+} -+ -+static inline void gpio_set_value(unsigned gpio, int value) -+{ -+ if (gpio <= MAX_UBICOM_ONCHIP_GPIO) -+ { -+ UBICOM32_GPIO_SET_PIN(gpio, value); -+ } -+ else -+ { -+ __gpio_set_value(gpio, value); -+ } -+} -+ -+static inline int gpio_cansleep(unsigned gpio) -+{ -+ return __gpio_cansleep(gpio); -+} -+ -+static inline int gpio_to_irq(unsigned gpio) -+{ -+#if defined(IP5000) || defined(IP5000_REV2) -+ if ((gpio >= GPIO_RA_4) && (gpio <= GPIO_RA_6)) -+ return 25; -+ else -+ return -ENXIO; -+ -+#elif defined(IP7000) || defined(IP7000_REV2) -+ if ((gpio >= GPIO_RA_4) && (gpio <= GPIO_RA_6)) -+ return 44 + (gpio - GPIO_RA_4); -+ else -+ return -ENXIO; -+ -+#else -+ return -ENXIO; -+ -+#endif -+} -+ -+static inline int irq_to_gpio(unsigned gpio) -+{ -+ return -ENXIO; -+} -+ -+extern struct ubicom32_io_port *ubi_gpio_get_port(unsigned gpio); -+ -+extern int __init ubi_gpio_init(void); -+ -+#endif /* _ASM_UBICOM32_GPIO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/hardirq.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/hardirq.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/hardirq.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/hardirq.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,55 @@ -+/* -+ * arch/ubicom32/include/asm/hardirq.h -+ * Definition of ack_bad_irq() for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1997, 98, 99, 2000, 01, 05 Ralf Baechle (ralf@linux-mips.org) -+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. -+ * Copyright (C) 2001 MIPS Technologies, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_HARDIRQ_H -+#define _ASM_UBICOM32_HARDIRQ_H -+ -+#include -+#include -+ -+/* -+ * The hardirq mask has to be large enough to have space -+ * for potentially all IRQ sources in the system nesting -+ * on a single CPU. For Ubicom32, we have 64 IRQ sources. -+ */ -+#define HARDIRQ_BITS 6 -+#if (1 << HARDIRQ_BITS) < NR_IRQS -+# error HARDIRQ_BITS is too low! -+#endif -+ -+typedef struct { -+ unsigned int __softirq_pending; -+} ____cacheline_aligned irq_cpustat_t; -+ -+#include /* Standard mappings for irq_cpustat_t above */ -+ -+extern void ack_bad_irq(unsigned int irq); -+ -+#endif /* _ASM_UBICOM32_HARDIRQ_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/hw_irq.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/hw_irq.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/hw_irq.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/hw_irq.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,31 @@ -+/* -+ * arch/ubicom32/include/asm/hw_irq.h -+ * Ubicom32 architecture APIC support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_HW_IRQ_H -+#define _ASM_UBICOM32_HW_IRQ_H -+ -+#endif /* _ASM_UBICOM32_HW_IRQ_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ioctl.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ioctl.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ioctl.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ioctl.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/ioctl.h -+ * Generic ioctl.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_IOCTL_H -+#define _ASM_UBICOM32_IOCTL_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_IOCTL_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ioctls.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ioctls.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ioctls.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ioctls.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,111 @@ -+/* -+ * arch/ubicom32/include/asm/ioctls.h -+ * Definitions of ioctls for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_IOCTLS_H -+#define _ASM_UBICOM32_IOCTLS_H -+ -+#include -+ -+/* 0x54 is just a magic number to make these relatively unique ('T') */ -+ -+#define TCGETS 0x5401 -+#define TCSETS 0x5402 -+#define TCSETSW 0x5403 -+#define TCSETSF 0x5404 -+#define TCGETA 0x5405 -+#define TCSETA 0x5406 -+#define TCSETAW 0x5407 -+#define TCSETAF 0x5408 -+#define TCSBRK 0x5409 -+#define TCXONC 0x540A -+#define TCFLSH 0x540B -+#define TIOCEXCL 0x540C -+#define TIOCNXCL 0x540D -+#define TIOCSCTTY 0x540E -+#define TIOCGPGRP 0x540F -+#define TIOCSPGRP 0x5410 -+#define TIOCOUTQ 0x5411 -+#define TIOCSTI 0x5412 -+#define TIOCGWINSZ 0x5413 -+#define TIOCSWINSZ 0x5414 -+#define TIOCMGET 0x5415 -+#define TIOCMBIS 0x5416 -+#define TIOCMBIC 0x5417 -+#define TIOCMSET 0x5418 -+#define TIOCGSOFTCAR 0x5419 -+#define TIOCSSOFTCAR 0x541A -+#define FIONREAD 0x541B -+#define TIOCINQ FIONREAD -+#define TIOCLINUX 0x541C -+#define TIOCCONS 0x541D -+#define TIOCGSERIAL 0x541E -+#define TIOCSSERIAL 0x541F -+#define TIOCPKT 0x5420 -+#define FIONBIO 0x5421 -+#define TIOCNOTTY 0x5422 -+#define TIOCSETD 0x5423 -+#define TIOCGETD 0x5424 -+#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -+#define TIOCSBRK 0x5427 /* BSD compatibility */ -+#define TIOCCBRK 0x5428 /* BSD compatibility */ -+#define TIOCGSID 0x5429 /* Return the session ID of FD */ -+#define TCGETS2 _IOR('T',0x2A, struct termios2) -+#define TCSETS2 _IOW('T',0x2B, struct termios2) -+#define TCSETSW2 _IOW('T',0x2C, struct termios2) -+#define TCSETSF2 _IOW('T',0x2D, struct termios2) -+#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -+#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ -+ -+#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ -+#define FIOCLEX 0x5451 -+#define FIOASYNC 0x5452 -+#define TIOCSERCONFIG 0x5453 -+#define TIOCSERGWILD 0x5454 -+#define TIOCSERSWILD 0x5455 -+#define TIOCGLCKTRMIOS 0x5456 -+#define TIOCSLCKTRMIOS 0x5457 -+#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ -+#define TIOCSERGETLSR 0x5459 /* Get line status register */ -+#define TIOCSERGETMULTI 0x545A /* Get multiport config */ -+#define TIOCSERSETMULTI 0x545B /* Set multiport config */ -+ -+#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ -+#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -+#define FIOQSIZE 0x545E -+ -+/* Used for packet mode */ -+#define TIOCPKT_DATA 0 -+#define TIOCPKT_FLUSHREAD 1 -+#define TIOCPKT_FLUSHWRITE 2 -+#define TIOCPKT_STOP 4 -+#define TIOCPKT_START 8 -+#define TIOCPKT_NOSTOP 16 -+#define TIOCPKT_DOSTOP 32 -+ -+#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -+ -+#endif /* _ASM_UBICOM32_IOCTLS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/io.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/io.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/io.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/io.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,313 @@ -+/* -+ * arch/ubicom32/include/asm/io.h -+ * I/O memory accessor functions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_IO_H -+#define _ASM_UBICOM32_IO_H -+ -+#ifdef __KERNEL__ -+#include -+#include -+ -+static inline unsigned short _swapw(volatile unsigned short v) -+{ -+ return ((v << 8) | (v >> 8)); -+} -+ -+static inline unsigned int _swapl(volatile unsigned long v) -+{ -+ return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24)); -+} -+ -+#ifndef CONFIG_PCI -+#define readb(addr) \ -+ ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; }) -+#define readw(addr) \ -+ ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; }) -+#define readl(addr) \ -+ ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; }) -+ -+#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b)) -+#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b)) -+#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b)) -+#else /*CONFIG_PCI */ -+ -+#define PCI_CPU_REG_BASE (0x00000000UL) /* taking lower 2GB space */ -+#define PCI_DEV_REG_BASE (0x80000000UL) -+ -+#if PCI_CPU_REG_BASE > PCI_DEV_REG_BASE -+#define IS_PCI_ADDRESS(x) (((unsigned int)(x)&(PCI_CPU_REG_BASE)) == 0) -+#else -+#define IS_PCI_ADDRESS(x) ((unsigned int)(x)&(PCI_DEV_REG_BASE)) -+#endif -+ -+extern unsigned int ubi32_pci_read_u32(const volatile void __iomem *addr); -+extern unsigned short ubi32_pci_read_u16(const volatile void __iomem *addr); -+extern unsigned char ubi32_pci_read_u8(const volatile void __iomem *addr); -+extern void ubi32_pci_write_u32(unsigned int val, const volatile void __iomem *addr); -+extern void ubi32_pci_write_u16(unsigned short val, const volatile void __iomem *addr); -+extern void ubi32_pci_write_u8(unsigned char val, const volatile void __iomem *addr); -+ -+static inline unsigned char readb(const volatile void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ return ubi32_pci_read_u8(addr); -+ else -+ return (unsigned char)(*(volatile unsigned char *)addr); -+} -+static inline unsigned short readw(const volatile void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ return ubi32_pci_read_u16(addr); -+ else -+ return (unsigned short)(*(volatile unsigned short *)addr); -+} -+ -+static inline unsigned int readl(const volatile void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ return ubi32_pci_read_u32(addr); -+ else -+ return (unsigned int)(*(volatile unsigned int *)addr); -+} -+ -+static inline void writel(unsigned int val, volatile void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ ubi32_pci_write_u32(val, addr); -+ else -+ *(volatile unsigned int *)addr = val; -+} -+ -+static inline void writew(unsigned short val, volatile void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ ubi32_pci_write_u16(val, addr); -+ else -+ *(volatile unsigned short *)addr = val; -+} -+ -+static inline void writeb(unsigned char val, volatile void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ ubi32_pci_write_u8(val, addr); -+ else -+ *(volatile unsigned char *)addr = val; -+} -+#endif -+ -+#define readb_relaxed(addr) readb(addr) -+#define readw_relaxed(addr) readw(addr) -+#define readl_relaxed(addr) readl(addr) -+ -+ -+#define __raw_readb readb -+#define __raw_readw readw -+#define __raw_readl readl -+#define __raw_writeb writeb -+#define __raw_writew writew -+#define __raw_writel writel -+ -+static inline void io_outsb(unsigned int addr, const void *buf, int len) -+{ -+ volatile unsigned char *ap = (volatile unsigned char *) addr; -+ unsigned char *bp = (unsigned char *) buf; -+ while (len--) -+ *ap = *bp++; -+} -+ -+static inline void io_outsw(unsigned int addr, const void *buf, int len) -+{ -+ volatile unsigned short *ap = (volatile unsigned short *) addr; -+ unsigned short *bp = (unsigned short *) buf; -+ while (len--) -+ *ap = _swapw(*bp++); -+} -+ -+static inline void io_outsl(unsigned int addr, const void *buf, int len) -+{ -+ volatile unsigned int *ap = (volatile unsigned int *) addr; -+ unsigned int *bp = (unsigned int *) buf; -+ while (len--) -+ *ap = _swapl(*bp++); -+} -+ -+static inline void io_insb(unsigned int addr, void *buf, int len) -+{ -+ volatile unsigned char *ap = (volatile unsigned char *) addr; -+ unsigned char *bp = (unsigned char *) buf; -+ while (len--) -+ *bp++ = *ap; -+} -+ -+static inline void io_insw(unsigned int addr, void *buf, int len) -+{ -+ volatile unsigned short *ap = (volatile unsigned short *) addr; -+ unsigned short *bp = (unsigned short *) buf; -+ while (len--) -+ *bp++ = _swapw(*ap); -+} -+ -+static inline void io_insl(unsigned int addr, void *buf, int len) -+{ -+ volatile unsigned int *ap = (volatile unsigned int *) addr; -+ unsigned int *bp = (unsigned int *) buf; -+ while (len--) -+ *bp++ = _swapl(*ap); -+} -+ -+#define mmiowb() -+ -+/* -+ * make the short names macros so specific devices -+ * can override them as required -+ */ -+#ifndef CONFIG_PCI -+#define memset_io(a,b,c) memset((void *)(a),(b),(c)) -+#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) -+#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) -+#else -+extern void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len); -+extern void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len); -+extern void memset_io(volatile void __iomem *addr, int val, size_t count); -+#endif -+ -+#define inb(addr) readb(addr) -+#define inw(addr) readw(addr) -+#define inl(addr) readl(addr) -+#define outb(x,addr) ((void) writeb(x,addr)) -+#define outw(x,addr) ((void) writew(x,addr)) -+#define outl(x,addr) ((void) writel(x,addr)) -+ -+#define inb_p(addr) inb(addr) -+#define inw_p(addr) inw(addr) -+#define inl_p(addr) inl(addr) -+#define outb_p(x,addr) outb(x,addr) -+#define outw_p(x,addr) outw(x,addr) -+#define outl_p(x,addr) outl(x,addr) -+ -+#define outsb(a,b,l) io_outsb(a,b,l) -+#define outsw(a,b,l) io_outsw(a,b,l) -+#define outsl(a,b,l) io_outsl(a,b,l) -+ -+#define insb(a,b,l) io_insb(a,b,l) -+#define insw(a,b,l) io_insw(a,b,l) -+#define insl(a,b,l) io_insl(a,b,l) -+ -+#ifndef CONFIG_PCI -+#define ioread8_rep(a,d,c) insb(a,d,c) -+#define ioread16_rep(a,d,c) insw(a,d,c) -+#define ioread32_rep(a,d,c) insl(a,d,c) -+#define iowrite8_rep(a,s,c) outsb(a,s,c) -+#define iowrite16_rep(a,s,c) outsw(a,s,c) -+#define iowrite32_rep(a,s,c) outsl(a,s,c) -+#else -+extern void ioread8_rep(void __iomem *port, void *buf, unsigned long count); -+extern void ioread16_rep(void __iomem *port, void *buf, unsigned long count); -+extern void ioread32_rep(void __iomem *port, void *buf, unsigned long count); -+extern void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count); -+extern void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count); -+extern void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count); -+#endif -+ -+ -+#ifndef CONFIG_PCI -+#define ioread8(X) readb(X) -+#define ioread16(X) readw(X) -+#define ioread32(X) readl(X) -+#define iowrite8(val,X) writeb(val,X) -+#define iowrite16(val,X) writew(val,X) -+#define iowrite32(val,X) writel(val,X) -+#else /*CONFIG_PCI */ -+extern unsigned char ioread8(void __iomem *addr); -+extern unsigned short ioread16(void __iomem *addr); -+extern unsigned int ioread32(void __iomem *addr); -+extern void iowrite8(unsigned char val, void __iomem *addr); -+extern void iowrite16(unsigned short val, void __iomem *addr); -+extern void iowrite32(unsigned int val, void __iomem *addr); -+#endif /* CONFIG_PCI */ -+ -+#define IO_SPACE_LIMIT 0xffff -+ -+/* Values for nocacheflag and cmode */ -+#define IOMAP_FULL_CACHING 0 -+#define IOMAP_NOCACHE_SER 1 -+#define IOMAP_NOCACHE_NONSER 2 -+#define IOMAP_WRITETHROUGH 3 -+ -+extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag); -+extern void __iounmap(void *addr, unsigned long size); -+ -+static inline void *ioremap(unsigned long physaddr, unsigned long size) -+{ -+ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); -+} -+static inline void *ioremap_nocache(unsigned long physaddr, unsigned long size) -+{ -+ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); -+} -+static inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size) -+{ -+ return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); -+} -+static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size) -+{ -+ return __ioremap(physaddr, size, IOMAP_FULL_CACHING); -+} -+ -+extern void iounmap(void *addr); -+ -+#define ioport_map(port, nr) ((void __iomem*)(port)) -+#define ioport_unmap(addr) -+ -+ -+/* Pages to physical address... */ -+#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) -+#define page_to_bus(page) ((page - mem_map) << PAGE_SHIFT) -+ -+/* -+ * Macros used for converting between virtual and physical mappings. -+ */ -+#define phys_to_virt(vaddr) ((void *) (vaddr)) -+#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) -+ -+#define virt_to_bus virt_to_phys -+#define bus_to_virt phys_to_virt -+ -+/* -+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem -+ * access -+ */ -+#define xlate_dev_mem_ptr(p) __va(p) -+ -+/* -+ * Convert a virtual cached pointer to an uncached pointer -+ */ -+#define xlate_dev_kmem_ptr(p) p -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _ASM_UBICOM32_IO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ip5000-asm.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ip5000-asm.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ip5000-asm.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ip5000-asm.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,156 @@ -+/* -+ * arch/ubicom32/include/asm/ip5000-asm.h -+ * Instruction macros for the IP5000. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_IP5000_ASM_H -+#define _ASM_UBICOM32_IP5000_ASM_H -+ -+#if !defined(__LINKER__) -+ -+#if defined(__ASSEMBLY__) -+.macro cycles quant -+.if (\quant) == 1 -+ nop -+.else -+.if (((\quant) + 3) / 8) > 0 -+.rept (((\quant) + 3) / 8) -+ jmpt.f .+4 -+.endr -+.endif -+.if ((((\quant) + 3) % 8) / 4) > 0 -+ jmpt.t .+4 -+.endif -+.endif -+.endm -+#else -+/* -+ * Same macro as above just in C inline asm -+ */ -+asm (" \n\ -+.macro cycles quant \n\ -+.if (\\quant) == 1 \n\ -+ nop \n\ -+.else \n\ -+.if (((\\quant) + 3) / 8) > 0 \n\ -+.rept (((\\quant) + 3) / 8) \n\ -+ jmpt.f .+4 \n\ -+.endr \n\ -+.endif \n\ -+.if ((((\\quant) + 3) % 8) / 4) > 0 \n\ -+ jmpt.t .+4 \n\ -+.endif \n\ -+.endif \n\ -+.endm \n\ -+"); -+#endif -+ -+ -+#if defined(__ASSEMBLY__) -+.macro pipe_flush cyc -+ cycles 11 - (\cyc) -+.endm -+#else -+/* -+ * Same macro as above just in C inline asm -+ */ -+asm (" \n\ -+.macro pipe_flush cyc \n\ -+ cycles 11 - (\\cyc) \n\ -+.endm \n\ -+"); -+ -+#endif -+ -+#if defined(__ASSEMBLY__) -+.macro setcsr_flush cyc -+ cycles 5 - (\cyc) -+.endm -+#else -+/* -+ * Same macro as above just in C inline asm -+ */ -+asm (" \n\ -+.macro setcsr_flush cyc \n\ -+ cycles 5 - (\\cyc) \n\ -+.endm \n\ -+"); -+#endif -+ -+/* -+ * Macros for prefetch (using miss-aligned memory write) -+ */ -+#if defined(__ASSEMBLY__) -+ -+.macro pre_fetch_macro thread_num, Ascratch, Aaddress length -+ bclr MT_TRAP_EN, MT_TRAP_EN, #(\thread_num) -+ bset \Ascratch, \Aaddress, #0 ; force a miss-aligned address -+ jmpt.t .+4 ; delay for both address setup and trap disable -+ move.4 (\Ascratch), #0 -+ .if (\length > 32) -+ move.4 32(\Ascratch), #0 -+ .endif -+ .if (\length > 64) -+ move.4 64(\Ascratch), #0 -+ .endif -+ .if (\length > 96) -+ move.4 96(\Ascratch), #0 -+ .endif -+ .if (\length > 128) -+ invalid_instruction ; maximum pre-fetch size is 4 cache lines -+ .endif -+ bset MT_TRAP_EN, MT_TRAP_EN, #(\thread_num) -+.endm -+ -+#else -+/* -+ * Same macro as above just in C inline asm -+ */ -+asm (" \n\ -+.macro pre_fetch_macro thread_num, Ascratch, Aaddress length \n\ -+ bclr MT_TRAP_EN, MT_TRAP_EN, #(\thread_num) \n\ -+ bset \\Ascratch, \\Aaddress, #0 ; force a miss-aligned address \n\ -+ jmpt.t .+4 ; delay for both address setup and trap disable \n\ -+ move.4 (\\Ascratch), #0 \n\ -+ .if (\\length > 32) \n\ -+ move.4 32(\\Ascratch), #0 \n\ -+ .endif \n\ -+ .if (\\length > 64) \n\ -+ move.4 64(\\Ascratch), #0 \n\ -+ .endif \n\ -+ .if (\\length > 96) \n\ -+ move.4 96(\\Ascratch), #0 \n\ -+ .endif \n\ -+ .if (\\length > 128) \n\ -+ invalid_instruction ; maximum pre-fetch size is 4 cache lines \n\ -+ .endif \n\ -+ bset MT_TRAP_EN, MT_TRAP_EN, #(\\thread_num) \n\ -+.endm \n\ -+"); -+#endif -+ -+#endif /* !defined(__LINKER__) */ -+#endif /* defined _ASM_UBICOM32_IP5000_ASM_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ip5000.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ip5000.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ip5000.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ip5000.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,845 @@ -+/* -+ * arch/ubicom32/include/asm/ip5000.h -+ * Specific details for the Ubicom IP5000 processor. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_IP5000_H -+#define _ASM_UBICOM32_IP5000_H -+ -+#include -+ -+/* -+ * Inline assembly define -+ */ -+#define S(arg) #arg -+#define D(arg) S(arg) -+ -+/* -+ * Assembler include file -+ */ -+#include -+ -+/* -+ * Timing -+ */ -+#define JMPT_PENALTY 3 -+#define JMPF_PENALTY 7 -+#define RET_PENALTY 7 -+ -+/* -+ * Threads -+ */ -+#if defined(IP5000) || defined(IP5000_REV2) -+#define THREAD_COUNT 10 -+#elif defined(IP7000) || defined(IP7000_REV2) -+#define THREAD_COUNT 12 -+#else -+#error "Unknown IP5K silicon" -+#endif -+ -+/* -+ * Arch -+ */ -+#if defined(IP5000) || defined(IP5000_REV2) -+#define UBICOM32_ARCH_VERSION 3 -+#elif defined(IP7000) || defined(IP7000_REV2) -+#define UBICOM32_ARCH_VERSION 4 -+#else -+#error "Unknown IP5K silicon" -+#endif -+ -+ -+/* -+ * Registers -+ */ -+#define ROSR_INT (1 << 0) -+ -+/* Interrupts */ -+#define INT_CHIP(reg, bit) (((reg) << 5) | (bit)) -+#define INT_REG(interrupt) (((interrupt) >> 5) * 4) -+#define INT_SET(interrupt) 0x0114 + INT_REG(interrupt) -+#define INT_CLR(interrupt) 0x0124 + INT_REG(interrupt) -+#define INT_STAT(interrupt) 0x0104 + INT_REG(interrupt) -+#define INT_MASK(interrupt) 0x00C0 + INT_REG(interrupt) -+#define INT_BIT(interrupt) ((interrupt) & 0x1F) -+#define INT_BIT_MASK(interrupt) (1 << INT_BIT(interrupt)) -+ -+/* -+ * The LOCK_INT and THREAD_INT are used to wake up corresponding thread. They are sharing -+ * the same set of SW interrupt resource. -+ * -+ * LOCK_INT(n): One SW INT per NRT thread that can participate lock operation. -+ * The threads that can participate lock are application threads and DSR thread. -+ * (Lock locks - numbers are hard-coded in lock.h) -+ * THREAD_INT(n): One SW INT per HRT thread for wake up trigger. -+ */ -+#define LOCK_INT(thread) INT_CHIP(0, (thread)) -+#define THREAD_INT(thread) INT_CHIP(0, (thread)) -+ -+/* -+ * The SYSTEM_INT and DSR_INT are sharing the same set of SW interrupt resource. -+ * -+ * SYSTEM_INT(n): One SW INT per NRT threads (application threads) as system queue interrupt, -+ * and for DSR as self-trigger interrupt. -+ * (The application threads include at least thread 0) -+ * DSR_INT(n): One SW INT per HRT thread to request DSR service. -+ */ -+#define SYSTEM_INT(thread) INT_CHIP(0, THREAD_COUNT + (thread)) -+#define DSR_INT(thread) INT_CHIP(0, THREAD_COUNT + (thread)) -+ -+/* GLOBAL_CTRL */ -+#define GLOBAL_CTRL_TRAP_RST_EN (1 << 9) -+#define GLOBAL_CTRL_AERROR_RST_EN (1 << 8) -+#define GLOBAL_CTRL_MT_MIN_DELAY(x) ((x) << 3) -+#define GLOBAL_CTRL_HRT_BANK_SELECT (1 << 2) -+#define GLOBAL_CTRL_INT_EN (1 << 0) -+ -+/* -+ * HRT Tables -+ */ -+#define HRT_TABLE0_BASE 0x0800 -+#define HRT_TABLE1_BASE 0x0900 -+#define HRT_TABLE_SIZE 64 -+ -+/* -+ * Break Point Trap Register -+ */ -+#define ASYNCERROR_INT INT_CHIP(0, 31) -+#define BREAKPOINT_INT INT_CHIP(1, 31) -+ -+/* -+ * Port interrupts -+ * The non-existing FIFO INTs are mapped to INT2 for the ports. -+ */ -+#define IO_PORT_PTR_TO_NUM(port) (((port) & 0x0000ffff) >> 12) -+#define RX_FIFO_INT(port) \ -+ ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 25) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 26) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 24) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 27) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 16) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 21) : \ -+ INT_CHIP(1, 15)))))))))) -+#define TX_FIFO_INT(port) \ -+ ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 24) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 27) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 25) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 28) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 17) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 22) : \ -+ INT_CHIP(1, 15)))))))))) -+#define PORT_OTHER_INT(port) \ -+ ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 25) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 28) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 26) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 29) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 18) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \ -+ ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 23) : \ -+ INT_CHIP(1, 15)))))))))) -+ -+/* -+ * On Chip Peripherals Base. -+ */ -+#define OCP_BASE 0x01000000 -+#define OCP_GENERAL 0x000 -+#define OCP_TIMERS 0x100 -+#define OCP_TRNG 0x200 /* True Random Number Generator Control Reigsters */ -+#define OCP_DEBUG 0x300 -+#define OCP_SECURITY 0x400 -+#define OCP_ICCR 0x500 /* I-Cache Control Registers */ -+#define OCP_DCCR 0x600 /* D-Cache Control Registers */ -+#define OCP_OCMC 0x700 /* On Chip Memory Control Registers */ -+#define OCP_STATISTICS 0x800 /* Statistics Counters */ -+#define OCP_MTEST 0x900 /* Memory Test Registers */ -+#define OCP_MCFG 0xa00 /* Memory Configuration Registers -- IP7000 only */ -+#define OCP_DEBUG_INST 0x000 /* Up to 16M */ -+ -+/* -+ * General Configuration Registers (PLL) -+ */ -+#define GENERAL_CFG_BASE (OCP_BASE + OCP_GENERAL) -+#define GEN_CLK_CORE_CFG 0x00 -+#define GEN_CLK_IO_CFG 0x04 -+#define GEN_CLK_DDR_CFG 0x08 -+#define GEN_CLK_DDRDS_CFG 0x0c -+#define GEN_CLK_SLIP_CLR 0x10 -+#define GEN_CLK_SLIP_START 0x14 -+#define GEN_CLK_SERDES_SEL 0x18 /* IP7000 only */ -+#define GEN_CLK_DDR_CFG2 0x1c /* IP7000 only */ -+#define GEN_DDR_CAL_CTRL 0x30 /* IP5000 only */ -+#define GEN_DDR_CAL_STAT 0x34 /* IP5000 only */ -+#define GEN_USB_DFT_CTRL 0x38 /* IP5000 only */ -+#define GEN_USB_DFT_STAT 0x3c /* IP5000 only */ -+#define GEN_USB_PHY_CFG 0x40 /* IP7000 only */ -+#define GEN_USB_PHY_TEST 0x44 /* IP7000 only */ -+#define GEN_USB_PHY_STAT 0x48 /* IP7000 only */ -+#define GEN_SW_RESET 0x80 -+#define GEN_RESET_REASON 0x84 -+#define GEN_BOND_CFG 0x88 -+#define GEN_IO_PU_CFG 0x8c -+#define GEN_MEM_RM_CFG 0x90 -+#define GEN_IO_CONFIG 0x94 -+ -+#define GEN_CLK_PLL_SECURITY_BIT_NO 31 -+#define GEN_CLK_PLL_SECURITY (1 << GEN_CLK_PLL_SECURITY_BIT_NO) -+#define GEN_CLK_PLL_ENSAT (1 << 30) -+#define GEN_CLK_PLL_FASTEN (1 << 29) -+#define GEN_CLK_PLL_NR(v) (((v) - 1) << 23) -+#define GEN_CLK_PLL_NF(v) (((v) - 1) << 11) -+#define GEN_CLK_PLL_OD(v) (((v) - 1) << 8) -+#define GEN_CLK_PLL_RESET (1 << 7) -+#define GEN_CLK_PLL_BYPASS (1 << 6) -+#define GEN_CLK_PLL_POWERDOWN (1 << 5) -+#define GEN_CLK_PLL_SELECT (1 << 4) -+ -+#define GEN_GET_CLK_PLL_NR(v) ((((v) >> 23) & 0x003f) + 1) -+#define GEN_GET_CLK_PLL_NF(v) ((((v) >> 11) & 0x0fff) + 1) -+#define GEN_GET_CLK_PLL_OD(v) ((((v) >> 8) & 0x7) + 1) -+ -+ -+#define RESET_FLAG_DST_MEM_ERROR (1 << 18) -+#define RESET_FLAG_SRC1_MEM_ERROR (1 << 17) -+#define RESET_FLAG_WRITE_ADDR (1 << 16) -+#define RESET_FLAG_DST_SYNC_ERROR (1 << 15) -+#define RESET_FLAG_SRC1_SYNC_ERROR (1 << 14) -+#define RESET_FLAG_DST_ALGN_ERROR (1 << 13) -+#define RESET_FLAG_SRC1_ALGN_ERROR (1 << 12) -+#define RESET_FLAG_DST_ADDR_ERROR (1 << 11) -+#define RESET_FLAG_SRC1_ADDR_ERROR (1 << 10) -+#define RESET_FLAG_ILLEGAL_INST (1 << 9) -+#define RESET_FLAG_INST_SYNC_ERROR (1 << 8) -+#define RESET_FLAG_INST_ADDR_ERROR (1 << 7) -+#define RESET_FLAG_DATA_PORT_ERROR (1 << 6) -+#define RESET_FLAG_INST_PORT_ERROR (1 << 5) -+#define RESET_FLAG_SW_RESET (1 << 4) -+#define RESET_FLAG_DEBUG (1 << 3) -+#define RESET_FLAG_WATCHDOG (1 << 2) -+#define RESET_FLAG_POWER_ON (1 << 1) -+#define RESET_FLAG_EXTERNAL (1 << 0) -+ -+/* -+ * Timer block -+ */ -+#define TIMER_BASE (OCP_BASE + OCP_TIMERS) -+#define TIMER_MPTVAL 0x00 -+#define TIMER_RTCOM 0x04 -+#define TIMER_TKEY 0x08 -+#define TIMER_WDCOM 0x0c -+#define TIMER_WDCFG 0x10 -+#define TIMER_SYSVAL 0x14 -+#define TIMER_SYSCOM(tmr) (0x18 + (tmr) * 4) -+#define TIMER_TRN_CFG 0x100 -+#define TIMER_TRN 0x104 -+ -+#define TIMER_COUNT 10 -+#define TIMER_INT(tmr) INT_CHIP(1, (tmr)) -+#define TIMER_TKEYVAL 0xa1b2c3d4 -+#define TIMER_WATCHDOG_DISABLE 0x4d3c2b1a -+#define TIMER_TRN_CFG_ENABLE_OSC 0x00000007 -+ -+#ifndef __ASSEMBLY__ -+/* -+ * ubicom32_io_timer -+ */ -+struct ubicom32_io_timer { -+ volatile u32_t mptval; -+ volatile u32_t rtcom; -+ volatile u32_t tkey; -+ volatile u32_t wdcom; -+ volatile u32_t wdcfg; -+ volatile u32_t sysval; -+ volatile u32_t syscom[TIMER_COUNT]; -+ volatile u32_t reserved[64 - 6 - TIMER_COUNT]; // skip all the way to OCP-TRNG section -+ volatile u32_t rsgcfg; -+ volatile u32_t trn; -+}; -+ -+#define UBICOM32_IO_TIMER ((struct ubicom32_io_timer *)TIMER_BASE) -+#endif -+ -+#define UBICOM32_VECTOR_TO_TIMER_INDEX(vector) (vector - TIMER_INT(0)) -+ -+/* -+ * OCP-Debug Module (Mailbox) -+ */ -+#define ISD_MAILBOX_BASE (OCP_BASE + OCP_DEBUG) -+#define ISD_MAILBOX_IN 0x00 -+#define ISD_MAILBOX_OUT 0x04 -+#define ISD_MAILBOX_STATUS 0x08 -+ -+#define ISD_MAILBOX_INT INT_CHIP(1, 30) -+ -+#define ISD_MAILBOX_STATUS_IN_FULL (1 << 31) -+#define ISD_MAILBOX_STATUS_IN_EMPTY (1 << 30) -+#define ISD_MAILBOX_STATUS_OUT_FULL (1 << 29) -+#define ISD_MAILBOX_STATUS_OUT_EMPTY (1 << 28) -+ -+/* -+ * OCP-Security -+ */ -+#define SECURITY_BASE (OCP_BASE + OCP_SECURITY) -+#define SECURITY_BASE_EFFECTIVE_ADDRESS (SECURITY_BASE >> 7) // To load the base address in a single instruction -+#define SECURITY_CTRL 0x00 -+#define SECURITY_CTRL_BYTE_OFFSET(x) ((x) << 16) -+#define SECURITY_CTRL_KEY_SIZE(x) ((x) << 8) -+#define SECURITY_CTRL_HASH_ALG_NONE (0 << 4) -+#define SECURITY_CTRL_HASH_ALG_MD5 (1 << 4) -+#define SECURITY_CTRL_HASH_ALG_SHA1 (2 << 4) -+#define SECURITY_CTRL_CBC (1 << 3) -+#define SECURITY_CTRL_CIPHER_ALG_AES (0 << 1) -+#define SECURITY_CTRL_CIPHER_ALG_NONE (1 << 1) -+#define SECURITY_CTRL_CIPHER_ALG_DES (2 << 1) -+#define SECURITY_CTRL_CIPHER_ALG_3DES (3 << 1) -+#define SECURITY_CTRL_ENCIPHER (1 << 0) -+#define SECURITY_CTRL_DECIPHER (0 << 0) -+#define SECURITY_STAT 0x04 -+#define SECURITY_STAT_BUSY (1 << 0) -+#define SECURITY_KEY_VALUE(x) (0x10 + (x) * 4) -+#define SECURITY_KEY_IN(x) (0x30 + (x) * 4) -+#define SECURITY_KEY_OUT(x) (0x50 + (x) * 4) -+#define SECURITY_KEY_HASH(x) (0x70 + (x) * 4) -+ -+/* -+ * OCP-ICCR -+ */ -+#define ICCR_BASE (OCP_BASE + OCP_ICCR) -+#define ICACHE_TOTAL_SIZE 16384 /* in bytes */ -+ -+/* -+ * OCP-DCCR -+ */ -+#define DCCR_BASE (OCP_BASE + OCP_DCCR) -+#if defined(IP5000) || defined(IP5000_REV2) -+#define DCACHE_TOTAL_SIZE 8192 /* in bytes */ -+#elif defined(IP7000) || defined(IP7000_REV2) -+#define DCACHE_TOTAL_SIZE 16384 /* in bytes */ -+#endif -+ -+#if defined(IP5000) || defined(IP5000_REV2) || defined(IP7000) || defined(IP7000_REV2) -+#define DCACHE_WRITE_QUEUE_LENGTH 6 -+#else -+#error "Unknown IP5K silicon" -+#endif -+ -+#define CACHE_LINE_SIZE 32 /* in bytes */ -+ -+#define CCR_ADDR 0x00 -+#define CCR_RDD 0x04 -+#define CCR_WRD 0x08 -+#define CCR_STAT 0x0c -+#define CCR_CTRL 0x10 -+ -+#define CCR_STAT_MCBE 0 -+#define CCR_STAT_WIDEL 1 /* D-cache only */ -+ -+#define CCR_CTRL_DONE 0 -+#define CCR_CTRL_RESET 2 -+#define CCR_CTRL_VALID 3 -+#define CCR_CTRL_RD_DATA (1 << 4) -+#define CCR_CTRL_RD_TAG (2 << 4) -+#define CCR_CTRL_WR_DATA (3 << 4) -+#define CCR_CTRL_WR_TAG (4 << 4) -+#define CCR_CTRL_INV_INDEX (5 << 4) -+#define CCR_CTRL_INV_ADDR (6 << 4) -+#define CCR_CTRL_FLUSH_INDEX (7 << 4) /* D-cache only */ -+#define CCR_CTRL_FLUSH_INV_INDEX (8 << 4) /* D-cache only */ -+#define CCR_CTRL_FLUSH_ADDR (9 << 4) /* D-cache only */ -+#define CCR_CTRL_FLUSH_INV_ADDR (10 << 4) /* D-cache only */ -+ -+/* -+ * OCP-OCMC -+ */ -+#define OCMC_BASE (OCP_BASE + OCP_OCMC) -+#define OCMC_BANK_MASK 0x00 -+#define OCMC_BIST_CNTL 0x04 /* IP5000 only */ -+#define OCMC_BIST_STAT 0x08 /* IP5000 only */ -+ -+#define OCMC_BANK_PROG(n) ((1<<(n))-1) -+ -+#define OCMC_BIST_WRCK (1 << 7) -+#define OCMC_BIST_RESET (1 << 5) -+#define OCMC_BIST_SMART (1 << 4) -+#define OCMC_BIST_RUN (1 << 3) -+#define OCMC_BIST_REPAIR (1 << 2) -+ -+#define OCMC_BIST_READY (1 << 3) -+#define OCMC_BIST_FAIL (1 << 2) -+ -+/* -+ * OCP-STATISTICS -+ */ -+#define STATISTICS_BASE (OCP_BASE + OCP_STATISTICS) -+#define STAT_COUNTER_CTRL(n) ((n)*8) -+#define STAT_COUNTER(n) ((n)*8 + 4) -+ -+#define STAT_EVENT_MP_INST 0 -+#define STAT_EVENT_OCM_ACCESS 4 -+#define STAT_EVENT_OCM_REQ 5 -+#define STAT_EVENT_IC_REQ_INVAL 13 -+#define STAT_EVENT_IC_MISS_INVAL 14 -+#define STAT_EVENT_IC_REQ_INVAL_NACK 15 -+#define STAT_EVENT_IC_REQ_VAL 16 -+#define STAT_EVENT_IC_MISS_VAL 17 -+#define STAT_EVENT_IC_REQ_VAL_NACK 18 -+#define STAT_EVENT_IC_MISS_Q 19 -+#define STAT_EVENT_DC_RD_REQ 20 -+#define STAT_EVENT_DC_RD_MISS 21 -+#define STAT_EVENT_DC_WR_REQ 22 -+#define STAT_EVENT_DC_WR_MISS 23 -+#define STAT_EVENT_DC_MISS_Q 24 -+#define STAT_EVENT_DC_WB_FULL 25 -+#define STAT_EVENT_DC_REQ_NACK 26 -+#define STAT_EVENT_DC_CORE_REQ 27 -+#define STAT_EVENT_DC_MISS 28 -+#define STAT_EVENT_DC_EVICT 29 -+#define STAT_EVENT_TRUE 30 -+#define STAT_EVENT_FALSE 31 -+ -+/* -+ * OCP_MTEST -+ */ -+#define MTEST_BASE (OCP_BASE + OCP_MTEST) -+#define MTEST_ADDR 0x00 -+#define MTEST_WR 0x04 -+#define MTEST_RD 0x08 -+#define MTEST_CTRL 0x0c -+ -+/* -+ * OCP_MCFG (IP7000 only) -+ */ -+#define MCFG_BASE (OCP_BASE + OCP_MCFG) -+#define MCFG_CTRL 0x00 -+#define MCFG_WCFG 0x04 -+#define MCFG_RCFG 0x08 -+ -+/* -+ * Port registers -+ */ -+#define IO_BASE 0x02000000 -+#define RA (IO_BASE + 0x00000000) -+#define RB (IO_BASE + 0x00001000) -+#define RC (IO_BASE + 0x00002000) -+#define RD (IO_BASE + 0x00003000) -+#define RE (IO_BASE + 0x00004000) -+#define RF (IO_BASE + 0x00005000) -+#define RG (IO_BASE + 0x00006000) -+#define RH (IO_BASE + 0x00007000) -+#define RI (IO_BASE + 0x00008000) -+#define RJ (IO_BASE + 0x00009000) -+#define RLATCH (IO_BASE + 0x00ff0000) // For latched output only -+#define IO_PORT_BR_OFFSET 0x00000800 -+ -+/* -+ * General I/O Register Map (per port) -+ */ -+#define IO_FUNC 0x00 -+#define IO_GPIO_CTL 0x04 -+#define IO_GPIO_OUT 0x08 -+#define IO_GPIO_IN 0x0C -+#define IO_INT_STATUS 0x10 -+#define IO_INT_MASK 0x14 -+#define IO_INT_SET 0x18 -+#define IO_INT_CLR 0x1C -+#define IO_TX_FIFO 0x20 -+#define IO_TX_FIFO_HI 0x24 -+#define IO_RX_FIFO 0x28 -+#define IO_RX_FIFO_HI 0x2c -+#define IO_CTL0 0x30 -+#define IO_CTL1 0x34 -+#define IO_CTL2 0x38 -+#define IO_STATUS0 0x3c -+#define IO_STATUS1 0x40 -+#define IO_STATUS2 0x44 -+#define IO_FIFO_WATER 0x48 -+#define IO_FIFO_LEVEL 0x4c -+#define IO_GPIO_MASK 0x50 -+ -+#define IO_FUNC_FUNCTION_RESET(func) ((1 << ((func) - 1)) << 4) /* Function 0 doesn't need reset */ -+#define IO_FUNC_RX_FIFO (1 << 3) -+#define IO_FUNC_SELECT(func) ((func) << 0) -+ -+/* -+ * External interrupt pins. -+ */ -+#define EXT_INT_IO_BIT(pin) ((pin) + 5) // Interrupt pin number -> I/O INT bit -+#define EXT_INT_RISING_EDGE(pin) (0x2 << (2*(pin) + 7)) -+#define EXT_INT_FALLING_EDGE(pin) (0x1 << (2*(pin) + 7)) -+ -+/* -+ * Flash -+ */ -+#define IO_XFL_BASE RA -+ -+#define IO_XFL_INT_START (1 << 16) -+#define IO_XFL_INT_ERR (1 << 8) -+#define IO_XFL_INT_DONE (1 << 0) -+ -+#define IO_XFL_CTL0_MASK (0xffe07fff) -+#define IO_XFL_CTL0_RD_CMD(cmd) (((cmd) & 0xff) << 24) -+#define IO_XFL_CTL0_RD_DUMMY(n) (((n) & 0x7) << 21) -+#define IO_XFL_CTL0_CLK_WIDTH(core_cycles) ((((core_cycles) + 1) & 0x7e) << 8) /* must be even number */ -+#define IO_XFL_CTL0_CE_WAIT(spi_cycles) (((spi_cycles) & 0x3f) << 2) -+#define IO_XFL_CTL0_MCB_LOCK (1 << 1) -+#define IO_XFL_CTL0_ENABLE (1 << 0) -+#define IO_XFL_CTL0_FAST_VALUE(div, wait) (IO_XFL_CTL0_RD_CMD(0xb) | IO_XFL_CTL0_RD_DUMMY(1) | IO_XFL_CTL0_CLK_WIDTH(div) | IO_XFL_CTL0_CE_WAIT(wait) | IO_XFL_CTL0_ENABLE) -+#define IO_XFL_CTL0_VALUE(div, wait) (IO_XFL_CTL0_RD_CMD(3) | IO_XFL_CTL0_CLK_WIDTH(div) | IO_XFL_CTL0_CE_WAIT(wait) | IO_XFL_CTL0_ENABLE) -+ -+#define IO_XFL_CTL1_MASK (0xc0003fff) -+#define IO_XFL_CTL1_FC_INST(inst) (((inst) & 0x3) << 30) -+#define IO_XFL_CTL1_FC_DATA(n) (((n) & 0x3ff) << 4) -+#define IO_XFL_CTL1_FC_DUMMY(n) (((n) & 0x7) << 1) -+#define IO_XFL_CTL1_FC_ADDR (1 << 0) -+ -+#define IO_XFL_CTL2_FC_CMD(cmd) (((cmd) & 0xff) << 24) -+#define IO_XFL_CTL2_FC_ADDR(addr) ((addr) & 0x00ffffff) /* Only up to 24 bits */ -+ -+#define IO_XFL_STATUS0_MCB_ACTIVE (1 << 0) -+#define IO_XFL_STATUS0_IOPCS_ACTIVE (1 << 1) -+ -+/* -+ * SDRAM -+ */ -+#define IO_SDRAM_DATA_BASE RG -+#define IO_SDRAM_CNTL_BASE RH -+ -+#define IO_SDRAM_CTRL0_EN_REF (1 << 0) -+ -+/* -+ * Port function code (common fucntion codes for all I/O ports) -+ */ -+#define IO_PORTX_FUNC_GPIO 0x00 -+#define IO_PORTX_FUNC_XFL 0x01 -+#define IO_PORTX_FUNC_PCI 0x01 -+#define IO_PORTX_FUNC_SERDES 0x01 -+#define IO_PORTX_FUNC_GMII 0x01 -+#define IO_PORTX_FUNC_DDR 0x01 -+#define IO_PORTX_FUNC_PCIX 0x01 -+#define IO_PORTX_FUNC_USB2_0 0x01 -+#define IO_PORTX_FUNC_GPIO_INT_CLK 0x02 -+#define IO_PORTX_FUNC_PLIO 0x02 -+#define IO_PORTX_FUNC_GPIO_INT 0x03 -+#define IO_PORTX_FUNC_MII 0x03 -+ -+/* -+ * Port 0 -+ */ -+#define IO_PORT0_FUNC_GPIO IO_PORTX_FUNC_GPIO -+#define IO_PORT0_FUNC_XFL_INT_CLK IO_PORTX_FUNC_XFL // Default mode after reset -+#define IO_PORT0_FUNC_GPIO_INT_CLK IO_PORTX_FUNC_GPIO_INT_CLK -+#define IO_PORT0_FUNC_GPIO_INT IO_PORTX_FUNC_GPIO_INT -+ -+/* -+ * Port 1 -+ */ -+#define IO_PORT1_FUNC_GPIO IO_PORTX_FUNC_GPIO -+#define IO_PORT1_FUNC_PCI IO_PORTX_FUNC_PCI // PCI control -+#define IO_PORT1_FUNC_MII IO_PORTX_FUNC_MII // port 4 MII extension -+ -+/* -+ * Port 2 -+ */ -+#define IO_PORT2_FUNC_GPIO IO_PORTX_FUNC_GPIO -+#define IO_PORT2_FUNC_PCI IO_PORTX_FUNC_PCI // PCI data I/O -+#define IO_PORT2_FUNC_PLIO IO_PORTX_FUNC_PLIO // Extended LM -+ -+/* -+ * Port 3 -+ */ -+#define IO_PORT3_FUNC_GPIO IO_PORTX_FUNC_GPIO -+#define IO_PORT3_FUNC_SERDES IO_PORTX_FUNC_SERDES -+#define IO_PORT3_FUNC_PLIO IO_PORTX_FUNC_PLIO -+ -+/* -+ * Port 4 -+ */ -+#define IO_PORT4_FUNC_GPIO IO_PORTX_FUNC_GPIO -+#define IO_PORT4_FUNC_SERDES IO_PORTX_FUNC_SERDES -+#define IO_PORT4_FUNC_PLIO IO_PORTX_FUNC_PLIO // Extended LM -+#define IO_PORT4_FUNC_MII IO_PORTX_FUNC_MII -+ -+/* -+ * Port 5 -+ */ -+#define IO_PORT5_FUNC_GPIO IO_PORTX_FUNC_GPIO -+#define IO_PORT5_FUNC_GMII IO_PORTX_FUNC_GMII -+ -+/* -+ * Port 6 -+ */ -+#define IO_PORT6_FUNC_GPIO IO_PORTX_FUNC_GPIO -+#define IO_PORT6_FUNC_DDR IO_PORTX_FUNC_DDR -+ -+/* -+ * Port 7 -+ */ -+#define IO_PORT7_FUNC_GPIO IO_PORTX_FUNC_GPIO -+#define IO_PORT7_FUNC_DDR IO_PORTX_FUNC_DDR -+ -+/* -+ * Port 8 -+ */ -+#define IO_PORT8_FUNC_GPIO IO_PORTX_FUNC_GPIO -+#define IO_PORT8_FUNC_PCIX IO_PORTX_FUNC_PCIX -+#define IO_PORT8_FUNC_PLIO IO_PORTX_FUNC_PLIO // Extended LM -+#define IO_PORT8_FUNC_MII IO_PORTX_FUNC_MII // port 4 MII extension -+ -+/* -+ * Port 9 -+ */ -+#define IO_PORT9_FUNC_USB2_0 IO_PORTX_FUNC_USB2_0 -+ -+/* -+ * FIFO -+ */ -+#define IO_PORTX_INT_FIFO_TX_RESET (1 << 31) -+#define IO_PORTX_INT_FIFO_RX_RESET (1 << 30) -+#define IO_PORTX_INT_FIFO_TX_UF (1 << 15) -+#define IO_PORTX_INT_FIFO_TX_WM (1 << 14) -+#define IO_PORTX_INT_FIFO_RX_OF (1 << 13) -+#define IO_PORTX_INT_FIFO_RX_WM (1 << 12) -+ -+#define IO_PORTX_FUNC_FIFO_TX_WM(n) ((n) << 16) -+#define IO_PORTX_FUNC_FIFO_RX_WM(n) ((n) << 0) -+ -+/* -+ * MII -+ */ -+#define IO_PORTX_INT_MII_TX_ERR_SEND (1 << 18) -+#define IO_PORTX_INT_MII_TX_HALT (1 << 17) -+#define IO_PORTX_INT_MII_TX_START (1 << 16) -+#define IO_PORTX_INT_MII_THRESHOLD (1 << 8) -+#define IO_PORTX_INT_MII_RX_EOP (1 << 7) -+#define IO_PORTX_INT_MII_RX_SFD (1 << 6) -+#define IO_PORTX_INT_MII_RX_ERR (1 << 5) -+#define IO_PORTX_INT_MII_TX_EOP (1 << 4) -+#define IO_PORTX_INT_MII_COL (1 << 3) -+#define IO_PORTX_INT_MII_CRS (1 << 2) -+#define IO_PORTX_INT_MII_ODD_NIB_ERR (1 << 1) -+#define IO_PORTX_INT_MII_FALSE_CARRIER (1 << 0) -+ -+/* -+ * SerDes -+ */ -+#define IO_PORTX_INT_SERDES_TXBUF_VALID (1 << 16) -+#define IO_PORTX_INT_SERDES_RXERR (1 << 7) -+#define IO_PORTX_INT_SERDES_RXEOP (1 << 6) -+#define IO_PORTX_INT_SERDES_SYND (1 << 5) -+#define IO_PORTX_INT_SERDES_TXBE (1 << 4) -+#define IO_PORTX_INT_SERDES_TXEOP (1 << 3) -+#define IO_PORTX_INT_SERDES_SXLP (1 << 2) -+#define IO_PORTX_INT_SERDES_RXBF (1 << 1) -+#define IO_PORTX_INT_SERDES_RXCRS (1 << 0) -+ -+#ifndef __ASSEMBLY__ -+struct ubicom32_io_port { -+ volatile u32_t function; -+ volatile u32_t gpio_ctl; -+ volatile u32_t gpio_out; -+ volatile u32_t gpio_in; -+ volatile u32_t int_status; -+ volatile u32_t int_mask; -+ volatile u32_t int_set; -+ volatile u32_t int_clr; -+ volatile u32_t tx_fifo; -+ volatile u32_t tx_fifo_hi; -+ volatile u32_t rx_fifo; -+ volatile u32_t rx_fifo_hi; -+ volatile u32_t ctl0; -+ volatile u32_t ctl1; -+ volatile u32_t ctl2; -+ volatile u32_t status0; -+ volatile u32_t status1; -+ volatile u32_t status2; -+ volatile u32_t fifo_watermark; -+ volatile u32_t fifo_level; -+ volatile u32_t gpio_mask; -+}; -+ -+#define UBICOM32_IO_PORT(port) ((struct ubicom32_io_port *)((port))) -+#endif -+ -+#ifndef __ASSEMBLY__ -+/* -+ * ubicom32_set_interrupt() -+ */ -+extern inline void ubicom32_set_interrupt(u8_t interrupt) -+{ -+ u32_t ibit = INT_BIT_MASK(interrupt); -+ -+ if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) { -+ asm volatile ( -+ "move.4 "D(INT_SET(INT_CHIP(0, 0)))", %0\n\t" -+ : -+ : "r" (ibit) -+ ); -+ -+ return; -+ } -+ -+ asm volatile ( -+ "move.4 "D(INT_SET(INT_CHIP(1, 0)))", %0\n\t" -+ : -+ : "r" (ibit) -+ ); -+} -+ -+/* -+ * ubicom32_clear_interrupt() -+ */ -+extern inline void ubicom32_clear_interrupt(u8_t interrupt) -+{ -+ u32_t ibit = INT_BIT_MASK(interrupt); -+ -+ if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) { -+ asm volatile ( -+ "move.4 "D(INT_CLR(INT_CHIP(0, 0)))", %0\n\t" -+ : -+ : "r" (ibit) -+ ); -+ -+ return; -+ } -+ -+ asm volatile ( -+ "move.4 "D(INT_CLR(INT_CHIP(1, 0)))", %0\n\t" -+ : -+ : "r" (ibit) -+ ); -+} -+ -+/* -+ * ubicom32_enable_interrupt() -+ */ -+extern inline void ubicom32_enable_interrupt(u8_t interrupt) -+{ -+ u32_t ibit = INT_BIT_MASK(interrupt); -+ -+ if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) { -+ asm volatile ( -+ "or.4 "D(INT_MASK(INT_CHIP(0, 0)))", "D(INT_MASK(INT_CHIP(0, 0)))", %0\n\t" -+ : -+ : "d" (ibit) -+ ); -+ -+ return; -+ } -+ -+ asm volatile ( -+ "or.4 "D(INT_MASK(INT_CHIP(1, 0)))", "D(INT_MASK(INT_CHIP(1, 0)))", %0\n\t" -+ : -+ : "d" (ibit) -+ ); -+} -+ -+/* -+ * ubicom32_disable_interrupt() -+ */ -+extern inline void ubicom32_disable_interrupt(u8_t interrupt) -+{ -+ u32_t ibit = ~INT_BIT_MASK(interrupt); -+ -+ if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) { -+ asm volatile ( -+ "and.4 "D(INT_MASK(INT_CHIP(0, 0)))", "D(INT_MASK(INT_CHIP(0, 0)))", %0\n\t" -+ : -+ : "d" (ibit) -+ ); -+ -+ return; -+ } -+ -+ asm volatile ( -+ "and.4 "D(INT_MASK(INT_CHIP(1, 0)))", "D(INT_MASK(INT_CHIP(1, 0)))", %0\n\t" -+ : -+ : "d" (ibit) -+ ); -+} -+ -+/* -+ * ubicom32_enable_global_interrupts() -+ */ -+extern inline void ubicom32_enable_global_interrupts(void) -+{ -+ asm volatile( -+ "bset GLOBAL_CTRL, GLOBAL_CTRL, #%bit("D(GLOBAL_CTRL_INT_EN)")" -+ ); -+} -+ -+/* -+ * ubicom32_disable_global_interrupts() -+ */ -+extern inline void ubicom32_disable_global_interrupts(void) -+{ -+ asm volatile( -+ "bclr GLOBAL_CTRL, GLOBAL_CTRL, #%bit("D(GLOBAL_CTRL_INT_EN)")" -+ ); -+} -+ -+/* -+ * ubicom32_get_reset_reason() -+ */ -+extern inline u32_t ubicom32_get_reset_reason(void) -+{ -+ return *(u32_t *)(GENERAL_CFG_BASE + GEN_RESET_REASON); -+} -+ -+/* -+ * ubicom32_read_reg() -+ */ -+extern inline u32_t ubicom32_read_reg(volatile void *reg) -+{ -+ u32_t v; -+ asm volatile ( -+ "move.4 %[dest], %[src] \n\t" -+ : [dest] "=r" (v) -+ : [src] "m" (*(u32_t *)reg) -+ ); -+ return v; -+} -+ -+/* -+ * ubicom32_write_reg() -+ */ -+extern inline void ubicom32_write_reg(volatile void *reg, u32_t v) -+{ -+ asm volatile ( -+ "move.4 %[dest], %[src] \n\t" -+ : -+ : [src] "r" (v), [dest] "m" (*(u32_t *)reg) -+ ); -+} -+ -+#endif /* __ASSEMBLY__ */ -+#endif /* _ASM_UBICOM32_IP5000_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ipcbuf.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ipcbuf.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ipcbuf.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ipcbuf.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,55 @@ -+/* -+ * arch/ubicom32/include/asm/ipcbuf.h -+ * Definition of ipc64_perm struct for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_IPCBUF_H -+#define _ASM_UBICOM32_IPCBUF_H -+ -+/* -+ * The user_ipc_perm structure for m68k architecture. -+ * Note extra padding because this structure is passed back and forth -+ * between kernel and user space. -+ * -+ * Pad space is left for: -+ * - 32-bit mode_t and seq -+ * - 2 miscellaneous 32-bit values -+ */ -+struct ipc64_perm -+{ -+ __kernel_key_t key; -+ __kernel_uid32_t uid; -+ __kernel_gid32_t gid; -+ __kernel_uid32_t cuid; -+ __kernel_gid32_t cgid; -+ __kernel_mode_t mode; -+ unsigned short __pad1; -+ unsigned short seq; -+ unsigned short __pad2; -+ unsigned long __unused1; -+ unsigned long __unused2; -+}; -+ -+#endif /* _ASM_UBICOM32_IPCBUF_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/irqflags.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/irqflags.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/irqflags.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/irqflags.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,96 @@ -+/* -+ * arch/ubicom32/include/asm/irqflags.h -+ * Raw implementation of local IRQ functions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_IRQFLAGS_H -+#define _ASM_UBICOM32_IRQFLAGS_H -+ -+#include -+#include -+#if defined(CONFIG_SMP) -+#include -+#endif -+#include -+ -+#if defined(CONFIG_PREEMPT) -+#error Not supported by Ubicom32 irq handling, yet! -+#endif -+ -+/* -+ * raw_local_irq_enable() -+ * Enable interrupts for this thread. -+ */ -+static inline void raw_local_irq_enable(void) -+{ -+ ldsr_local_irq_enable(); -+} -+ -+/* -+ * raw_local_irq_disable() -+ * Disable interrupts for this thread. -+ */ -+static inline void raw_local_irq_disable(void) -+{ -+ ldsr_local_irq_disable(); -+} -+ -+/* -+ * raw_local_save_flags() -+ * Get the current IRQ state. -+ */ -+#define raw_local_save_flags(flags) \ -+do { \ -+ (flags) = ldsr_local_irq_is_disabled(); \ -+} while (0) -+ -+/* -+ * raw_local_irq_save() -+ * Save the current interrupt state and disable interrupts. -+ */ -+#define raw_local_irq_save(flags) \ -+do { \ -+ (flags) = ldsr_local_irq_save(); \ -+} while (0) -+ -+/* -+ * raw_local_irq_restore() -+ * Restore the IRQ state back to flags. -+ */ -+static inline void raw_local_irq_restore(unsigned long flags) -+{ -+ ldsr_local_irq_restore(flags); -+} -+ -+/* -+ * raw_irqs_disabled_flags() -+ * Return true if the flags indicate that IRQ(s) are disabled. -+ */ -+static inline int raw_irqs_disabled_flags(unsigned long flags) -+{ -+ return (flags); -+} -+ -+#endif /* _ASM_UBICOM32_IRQFLAGS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/irq.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/irq.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/irq.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/irq.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,45 @@ -+/* -+ * arch/ubicom32/include/asm/irq.h -+ * IRQ definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_IRQ_H -+#define _ASM_UBICOM32_IRQ_H -+ -+#include -+ -+/* -+ * We setup the IRQS to cover the full range of interrupt registers in -+ * processor. -+ */ -+#define NR_IRQS 64 -+ -+#define irq_canonicalize(irq) (irq) -+ -+extern int irq_soft_alloc(unsigned int *soft); -+extern void ack_bad_irq(unsigned int irq); -+extern void do_IRQ(int irq, struct pt_regs *fp); -+ -+#endif /* _ASM_UBICOM32_IRQ_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/irq_regs.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/irq_regs.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/irq_regs.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/irq_regs.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/irq_regs.h -+ * Generic irq_regs.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_IRQ_REGS_H -+#define _ASM_UBICOM32_IRQ_REGS_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_IRQ_REGS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/Kbuild linux-2.6.30.10-ubi/arch/ubicom32/include/asm/Kbuild ---- linux-2.6.30.10/arch/ubicom32/include/asm/Kbuild 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/Kbuild 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1 @@ -+include include/asm-generic/Kbuild.asm -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/kdebug.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/kdebug.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/kdebug.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/kdebug.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/kdebug.h -+ * Generic kdebug.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_KDEBUG_H -+#define _ASM_UBICOM32_KDEBUG_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_KDEBUG_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/kmap_types.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/kmap_types.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/kmap_types.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/kmap_types.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,48 @@ -+/* -+ * arch/ubicom32/include/asm/kmap_types.h -+ * Definition of km_type's for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_KMAP_TYPES_H -+#define _ASM_UBICOM32_KMAP_TYPES_H -+ -+enum km_type { -+ KM_BOUNCE_READ, -+ KM_SKB_SUNRPC_DATA, -+ KM_SKB_DATA_SOFTIRQ, -+ KM_USER0, -+ KM_USER1, -+ KM_BIO_SRC_IRQ, -+ KM_BIO_DST_IRQ, -+ KM_PTE0, -+ KM_PTE1, -+ KM_IRQ0, -+ KM_IRQ1, -+ KM_SOFTIRQ0, -+ KM_SOFTIRQ1, -+ KM_TYPE_NR -+}; -+ -+#endif /* _ASM_UBICOM32_KMAP_TYPES_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ldsr.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ldsr.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ldsr.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ldsr.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,186 @@ -+/* -+ * arch/ubicom32/include/asm/ldsr.h -+ * Ubicom32 LDSR interface definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_LDSR_H -+#define _ASM_UBICOM32_LDSR_H -+ -+#include -+#include -+#include -+ -+extern unsigned int ldsr_soft_irq_mask; -+ -+/* -+ * ldsr_local_irq_is_disabled() -+ * Test if interrupts are disabled for this thread? -+ */ -+static inline int ldsr_local_irq_is_disabled(void) -+{ -+ int ret; -+ thread_t self = thread_get_self(); -+ unsigned int mask = (1 << self); -+ -+ asm volatile ( -+ " and.4 %0, scratchpad1, %1 \n\t" -+ : "=r" (ret) -+ : "d" (mask) -+ : "cc" -+ ); -+ -+ /* -+ * We return a simple 1 == disabled, 0 == enabled -+ * losing which tid this is for, because Linux -+ * can restore interrupts on a different thread. -+ */ -+ return ret >> self; -+} -+ -+/* -+ * ldsr_local_irq_save() -+ * Get the current interrupt state and disable interrupts. -+ */ -+static inline unsigned int ldsr_local_irq_save(void) -+{ -+ int ret; -+ thread_t self = thread_get_self(); -+ unsigned int mask = (1 << self); -+ -+ /* -+ * Ensure the compiler can not optimize out the code -+ * (volatile) and that it does not "cache" values around -+ * the interrupt state change (memory). This ensures -+ * that interrupt changes are treated as a critical -+ * section. -+ */ -+ asm volatile ( -+ " and.4 %0, scratchpad1, %1 \n\t" -+ " or.4 scratchpad1, scratchpad1, %1 \n\t" -+ : "=&r" (ret) -+ : "d" (mask) -+ : "cc", "memory" -+ ); -+ -+ /* -+ * We return a simple 1 == disabled, 0 == enabled -+ * losing which tid this is for, because Linux -+ * can restore interrupts on a different thread. -+ */ -+ return ret >> self; -+} -+ -+/* -+ * ldsr_local_irq_restore() -+ * Restore this cpu's interrupt enable/disable state. -+ * -+ * Note: flags is either 0 or 1. -+ */ -+static inline void ldsr_local_irq_restore(unsigned int flags) -+{ -+ unsigned int temp; -+ thread_t self = thread_get_self(); -+ unsigned int mask = (1 << self); -+ flags = (flags << self); -+ -+ /* -+ * Ensure the compiler can not optimize out the code -+ * (volatile) and that it does not "cache" values around -+ * the interrupt state change (memory). This ensures -+ * that interrupt changes are treated as a critical -+ * section. -+ * -+ * Atomic change to our bit in scratchpad1 without -+ * causing any temporary glitch in the value and -+ * without effecting other values. Also this uses -+ * no branches so no penalties. -+ */ -+ asm volatile ( -+ " xor.4 %0, scratchpad1, %1 \n\t" -+ " and.4 %0, %2, %0 \n\t" -+ " xor.4 scratchpad1, scratchpad1, %0 \n\t" -+ " move.4 int_set0, %3 \n\t" -+ : "=&d"(temp) -+ : "d"(flags), "r"(mask), "r"(ldsr_soft_irq_mask) -+ : "cc", "memory" -+ ); -+} -+ -+/* -+ * ldsr_local_irq_disable_interrupt() -+ * Disable ints for this thread. -+ */ -+static inline void ldsr_local_irq_disable(void) -+{ -+ unsigned int mask = (1 << thread_get_self()); -+ -+ /* -+ * Ensure the compiler can not optimize out the code -+ * (volatile) and that it does not "cache" values around -+ * the interrupt state change (memory). This ensures -+ * that interrupt changes are treated as a critical -+ * section. -+ */ -+ asm volatile ( -+ " or.4 scratchpad1, scratchpad1, %0 \n\t" -+ : -+ : "d" (mask) -+ : "cc", "memory" -+ ); -+} -+ -+/* -+ * ldsr_local_irq_enable_interrupt -+ * Enable ints for this thread. -+ */ -+static inline void ldsr_local_irq_enable(void) -+{ -+ unsigned int mask = (1 << thread_get_self()); -+ -+ /* -+ * Ensure the compiler can not optimize out the code -+ * (volatile) and that it does not "cache" values around -+ * the interrupt state change (memory). This ensures -+ * that interrupt changes are treated as a critical -+ * section. -+ */ -+ asm volatile ( -+ " and.4 scratchpad1, scratchpad1, %0 \n\t" -+ " move.4 int_set0, %1 \n\t" -+ : -+ : "d" (~mask), "r" (ldsr_soft_irq_mask) -+ : "cc", "memory" -+ ); -+} -+ -+extern void ldsr_init(void); -+extern void ldsr_set_trap_irq(unsigned int irq); -+extern void ldsr_mask_vector(unsigned int vector); -+extern void ldsr_unmask_vector(unsigned int vector); -+extern void ldsr_enable_vector(unsigned int vector); -+extern void ldsr_disable_vector(unsigned int vector); -+extern thread_t ldsr_get_threadid(void); -+ -+#endif /* _ASM_UBICOM32_LDSR_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/linkage.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/linkage.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/linkage.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/linkage.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,34 @@ -+/* -+ * arch/ubicom32/include/asm/linkage.h -+ * Definition of Ubicom32 architecture specific linkage types. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_LINKAGE_H -+#define _ASM_UBICOM32_LINKAGE_H -+ -+#define __ocm_text __section(.ocm_text) -+#define __ocm_data __section(.ocm_data) -+ -+#endif /* _ASM_UBICOM32_LINKAGE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/local.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/local.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/local.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/local.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/local.h -+ * Generic local.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_LOCAL_H -+#define _ASM_UBICOM32_LOCAL_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_LOCAL_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/machdep.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/machdep.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/machdep.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/machdep.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,43 @@ -+/* -+ * arch/ubicom32/include/asm/machdep.h -+ * Machine dependent utility routines. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_MACHDEP_H -+#define _ASM_UBICOM32_MACHDEP_H -+ -+#include -+ -+/* Hardware clock functions */ -+extern unsigned long hw_timer_offset(void); -+ -+/* machine dependent power off functions */ -+extern void (*mach_reset)(void); -+extern void (*mach_halt)(void); -+extern void (*mach_power_off)(void); -+ -+extern void config_BSP(char *command, int len); -+ -+#endif /* _ASM_UBICOM32_MACHDEP_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/mc146818rtc.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mc146818rtc.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/mc146818rtc.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mc146818rtc.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,36 @@ -+/* -+ * arch/ubicom32/include/asm/mc146818rtc.h -+ * Generic mc146818rtc.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+/* -+ * Machine dependent access functions for RTC registers. -+ */ -+#ifndef _ASM_UBICOM32_MC146818RTC_H -+#define _ASM_UBICOM32_MC146818RTC_H -+ -+/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */ -+ -+#endif /* _ASM_UBICOM32_MC146818RTC_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/memory_map.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/memory_map.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/memory_map.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/memory_map.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,66 @@ -+/* -+ * arch/ubicom32/include/asm/memory_map.h -+ * Machine memory maps/ -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_MEMORY_MAP_H -+#define _ASM_UBICOM32_MEMORY_MAP_H -+ -+/* -+ * Memory Size -+ */ -+#define OCM_SECTOR_SIZE 0x00008000 /* 32K */ -+ -+#if defined(CONFIG_UBICOM32_V3) -+#define OCMSIZE 0x00030000 /* 192K on-chip RAM for both program and data */ -+#elif defined(CONFIG_UBICOM32_V4) -+#define OCMSIZE 0x0003C000 /* 240K on-chip RAM for both program and data */ -+#else -+#error "Unknown IP5K silicon" -+#endif -+ -+#define OCMSTART 0x3ffc0000 /* alias from 0x03000000 for easy -+ * jump to/from SDRAM */ -+#define OCMEND (OCMSTART + OCMSIZE) -+ -+#define SDRAMSTART 0x40000000 -+ -+#define KERNELSTART (SDRAMSTART + 0x00400000) -+ -+#define FLASHSTART 0x60000000 -+ -+/* -+ * CODELOADER / OS_SYSCALL OCM Reservations -+ * Don't change these unless you know what you are doing. -+ */ -+#define CODELOADER_SIZE 0x30 -+#define CODELOADER_BEGIN OCMSTART /* Must be OCM start for gdb to work. */ -+#define CODELOADER_END (CODELOADER_BEGIN + CODELOADER_SIZE) -+ -+#define OS_SYSCALL_BEGIN CODELOADER_END /* system_call at this address */ -+#define OS_SYSCALL_SIZE (512 - CODELOADER_SIZE) -+#define OS_SYSCALL_END (OS_SYSCALL_BEGIN + OS_SYSCALL_SIZE) -+ -+#endif /* _ASM_UBICOM32_MEMORY_MAP_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/mman.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mman.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/mman.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mman.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,44 @@ -+/* -+ * arch/ubicom32/include/asm/mman.h -+ * Memory mapping definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_MMAN_H -+#define _ASM_UBICOM32_MMAN_H -+ -+#include -+ -+#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ -+#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ -+#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ -+#define MAP_LOCKED 0x2000 /* pages are locked */ -+#define MAP_NORESERVE 0x4000 /* don't check for reservations */ -+#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ -+#define MAP_NONBLOCK 0x10000 /* do not block on IO */ -+ -+#define MCL_CURRENT 1 /* lock all current mappings */ -+#define MCL_FUTURE 2 /* lock all future mappings */ -+ -+#endif /* _ASM_UBICOM32_MMAN_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/mmu_context.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mmu_context.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/mmu_context.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mmu_context.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,60 @@ -+/* -+ * arch/ubicom32/include/asm/mmu_context.h -+ * MMU context definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2004, Microtronix Datacom Ltd., All rights reserved. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_MMU_CONTEXT_H -+#define _ASM_UBICOM32_MMU_CONTEXT_H -+ -+#include -+#include -+#include -+ -+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) -+{ -+} -+ -+extern inline int -+init_new_context(struct task_struct *tsk, struct mm_struct *mm) -+{ -+ // mm->context = virt_to_phys(mm->pgd); -+ return(0); -+} -+ -+#define destroy_context(mm) do { } while(0) -+ -+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) -+{ -+} -+ -+#define deactivate_mm(tsk,mm) do { } while (0) -+ -+extern inline void activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm) -+{ -+} -+ -+#endif /* _ASM_UBICOM32_MMU_CONTEXT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/mmu.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mmu.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/mmu.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mmu.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,41 @@ -+/* -+ * arch/ubicom32/include/asm/mmu.h -+ * Definition of mm_context_t struct for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2002, David McCullough -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_MMU_H -+#define _ASM_UBICOM32_MMU_H -+ -+typedef struct { -+ struct vm_list_struct *vmlist; -+ unsigned long end_brk; -+#ifdef CONFIG_BINFMT_ELF_FDPIC -+ unsigned long exec_fdpic_loadmap; -+ unsigned long interp_fdpic_loadmap; -+#endif -+} mm_context_t; -+ -+#endif /* _ASM_UBICOM32_MMU_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/module.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/module.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/module.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/module.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,48 @@ -+/* -+ * arch/ubicom32/include/asm/module.h -+ * Ubicom32 architecture specific module definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_MODULE_H -+#define _ASM_UBICOM32_MODULE_H -+ -+struct mod_arch_specific { -+ void *ocm_inst; -+ int ocm_inst_size; -+}; -+ -+#define Elf_Shdr Elf32_Shdr -+#define Elf_Sym Elf32_Sym -+#define Elf_Ehdr Elf32_Ehdr -+ -+#define ARCH_PROC_MODULES_EXTRA(m,mod) \ -+ seq_printf(m, " OCM(%d bytes @ 0x%p)", \ -+ (mod)->arch.ocm_inst_size, (mod)->arch.ocm_inst) -+ -+#define ARCH_OOPS_MODULE_EXTRA(mod) \ -+ printk(KERN_INFO "%p %u OCM(%p %u)\n", \ -+ (mod)->module_core, (mod)->core_size, \ -+ (mod)->arch.ocm_inst, (mod)->arch.ocm_inst_size) -+#endif /* _ASM_UBICOM32_MODULE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/msgbuf.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/msgbuf.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/msgbuf.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/msgbuf.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,58 @@ -+/* -+ * arch/ubicom32/include/asm/msgbuf.h -+ * Definition of msqid64_ds struct for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_MSGBUF_H -+#define _ASM_UBICOM32_MSGBUF_H -+ -+/* -+ * The msqid64_ds structure for ubicom32 architecture. -+ * Note extra padding because this structure is passed back and forth -+ * between kernel and user space. -+ * -+ * Pad space is left for: -+ * - 64-bit time_t to solve y2038 problem -+ * - 2 miscellaneous 32-bit values -+ */ -+ -+struct msqid64_ds { -+ struct ipc64_perm msg_perm; -+ __kernel_time_t msg_stime; /* last msgsnd time */ -+ unsigned long __unused1; -+ __kernel_time_t msg_rtime; /* last msgrcv time */ -+ unsigned long __unused2; -+ __kernel_time_t msg_ctime; /* last change time */ -+ unsigned long __unused3; -+ unsigned long msg_cbytes; /* current number of bytes on queue */ -+ unsigned long msg_qnum; /* number of messages in queue */ -+ unsigned long msg_qbytes; /* max number of bytes on queue */ -+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */ -+ __kernel_pid_t msg_lrpid; /* last receive pid */ -+ unsigned long __unused4; -+ unsigned long __unused5; -+}; -+ -+#endif /* _ASM_UBICOM32_MSGBUF_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/mutex.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mutex.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/mutex.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/mutex.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,41 @@ -+/* -+ * arch/ubicom32/include/asm/mutex.h -+ * Generic mutex.h for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+/* -+ * Pull in the generic implementation for the mutex fastpath. -+ * -+ * TODO: implement optimized primitives instead, or leave the generic -+ * implementation in place, or pick the atomic_xchg() based generic -+ * implementation. (see asm-generic/mutex-xchg.h for details) -+ */ -+ -+#ifndef _ASM_UBICOM32_MUTEX_H -+#define _ASM_UBICOM32_MUTEX_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_MUTEX_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/namei.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/namei.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/namei.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/namei.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,38 @@ -+/* -+ * arch/ubicom32/include/asm/namei.h -+ * Definition of __emul_prefix() for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_NAMEI_H -+#define _ASM_UBICOM32_NAMEI_H -+ -+/* This dummy routine maybe changed to something useful -+ * for /usr/gnemul/ emulation stuff. -+ * Look at asm-sparc/namei.h for details. -+ */ -+ -+#define __emul_prefix() NULL -+ -+#endif /* _ASM_UBICOM32_NAMEI_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ocm-alloc.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ocm-alloc.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ocm-alloc.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ocm-alloc.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,36 @@ -+/* -+ * arch/ubicom32/include/asm/ocm-alloc.h -+ * Ubicom32 architecture specific ocm definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_OCM_ALLOC_H -+#define _ASM_UBICOM32_OCM_ALLOC_H -+ -+ -+extern void *ocm_inst_alloc(size_t size, pid_t pid); -+extern int ocm_free(const void *ptr); -+extern int ocm_inst_free(const void *ptr); -+ -+#endif /* _ASM_UBICOM32_OCM_ALLOC_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ocm_size.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ocm_size.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ocm_size.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ocm_size.h 2009-12-14 14:30:27.000000000 +0200 -@@ -0,0 +1,3 @@ -+#define APP_OCM_CODE_SIZE (0x3ffc2e00-0x3ffc0000) -+#define APP_OCM_DATA_SIZE (0x3ffd3500-0x3ffc8000) -+ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ocm_text.lds.inc linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ocm_text.lds.inc ---- linux-2.6.30.10/arch/ubicom32/include/asm/ocm_text.lds.inc 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ocm_text.lds.inc 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,175 @@ -+/* -+ * arch/ubicom32/include/asm/ocm_text.lds.inc -+ * -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+*(.text.do_csum) -+*(.text.tcp_packet) -+*(.text.ipt_do_table) -+*(.text.nf_conntrack_in) -+*(.text.ip_forward) -+*(.text.dev_queue_xmit) -+*(.text.netif_receive_skb) -+*(.text.ip_route_input) -+*(.text.ip_finish_output) -+*(.text.nf_iterate) -+*(.text.__hash_conntrack) -+*(.text.memset) -+*(.text.memcpy) -+*(.text.ip_rcv) -+*(.text.__nf_conntrack_find) -+*(.text.dev_hard_start_xmit) -+*(.text.vlan_dev_hard_start_xmit) -+*(.text.vlan_dev_hard_header) -+*(.text.__nf_ct_refresh_acct) -+*(.text.tcp_error) -+*(.text.pfifo_fast_enqueue) -+*(.text.ipv4_confirm) -+*(.text.ip_output) -+*(.text.neigh_connected_output) -+*(.text.nf_hook_slow) -+*(.text.nf_nat_packet) -+*(.text.local_bh_enable) -+*(.text.pfifo_fast_dequeue) -+*(.text.ubi32_eth_receive) -+*(.text.nf_nat_fn) -+*(.text.skb_checksum) -+*(.text.memmove) -+*(.text.ubi32_eth_tx_done) -+*(.text.eth_header) -+*(.text.skb_release_data) -+*(.text.nf_conntrack_find_get) -+*(.text.process_backlog) -+*(.text.vlan_skb_recv) -+*(.text.ip_rcv_finish) -+*(.text.__qdisc_run) -+*(.text.skb_push) -+*(.text.eth_type_trans) -+*(.text.__alloc_skb) -+*(.text.netif_rx) -+*(.text.nf_ip_checksum) -+*(.text.__skb_checksum_complete_head) -+*(.text.ipv4_conntrack_defrag) -+*(.text.tcp_pkt_to_tuple) -+*(.text.kfree) -+*(.text.tcp_manip_pkt) -+*(.text.skb_put) -+*(.text.nf_ct_get_tuple) -+*(.text.__kmalloc) -+*(.text.ubi32_eth_start_xmit) -+*(.text.free_block) -+*(.text.ipt_hook) -+*(.text.kmem_cache_free) -+*(.text.skb_pull_rcsum) -+*(.text.cache_alloc_refill) -+*(.text.skb_release_head_state) -+*(.text.manip_pkt) -+*(.text.ip_sabotage_in) -+*(.text.ip_forward_finish) -+*(.text.kmem_cache_alloc) -+*(.text.local_bh_disable) -+*(.text.ipv4_pkt_to_tuple) -+*(.text.inet_proto_csum_replace4) -+*(.text.__nf_ct_l4proto_find) -+*(.text.csum_partial) -+*(.text.neigh_resolve_output) -+*(.text.__kfree_skb) -+*(.text.kfree_skb) -+*(.text.__find_vlan_dev) -+*(.text.ldsr_ctxsw_thread) -+*(.text.__do_IRQ) -+*(.text.skb_pull) -+*(.text.ipv4_invert_tuple) -+*(.text.nf_ct_invert_tuplepr) -+*(.text.skb_make_writable) -+*(.text.ipv4_get_l4proto) -+*(.text.handle_IRQ_event) -+*(.text.net_rx_action) -+*(.text.__do_softirq) -+*(.text.nf_nat_in) -+*(.text.note_interrupt) -+*(.text.ipv4_conntrack_in) -+*(.text.dst_release) -+*(.text.tasklet_action) -+*(.text.nf_nat_out) -+*(.text.nf_ct_invert_tuple) -+*(.text.do_IRQ) -+*(.text.__tasklet_schedule) -+*(.text.__skb_checksum_complete) -+*(.text.ubi32_eth_interrupt) -+*(.text.dev_kfree_skb_any) -+*(.text.ret_from_interrupt_to_kernel) -+*(.text.preemptive_context_save) -+*(.text.irq_ack_vector) -+*(.text.update_wall_time) -+*(.text.ldsr_thread) -+*(.text.irq_exit) -+*(.text.ubi32_eth_do_tasklet) -+*(.text.__napi_schedule) -+*(.text.idle_cpu) -+*(.text.run_timer_softirq) -+*(.text.ldsr_mask_vector) -+*(.text.irq_enter) -+*(.text.ldsr_get_lsb) -+*(.text.ldsr_unmask_vector) -+*(.text.ip_fast_csum) -+*(.text.hrtimer_run_queues) -+*(.text.tcp_invert_tuple) -+*(.text.T___705) -+*(.text.run_posix_cpu_timers) -+*(.text.free_hot_cold_page) -+*(.text.lock_timer_base) -+*(.text.calc_delta_mine) -+*(.text.slab_destroy) -+*(.text.rcu_pending) -+*(.text.scheduler_tick) -+*(.text.hrtimer_run_pending) -+*(.text.do_softirq) -+*(.text.del_timer) -+*(.text.irq_end_vector) -+*(.text.pci_read_u32) -+*(.text.udivmodsi4) -+*(.text.memcmp) -+*(.text.memset) -+*(.text.__slab_alloc) -+*(.text.br_handle_frame) -+*(.text.br_fdb_update) -+*(.text.__br_fdb_get) -+*(.text.br_forward) -+*(.text.br_handle_frame_finish) -+*(.text.pci_write_u32) -+*(.text.kmem_freepages) -+*(.text.br_dev_queue_push_xmit) -+*(.text.ioread32) -+*(.text.next_zones_zonelist) -+*(.text.ubi32_pci_read_u32) -+*(.text.zone_watermark_ok) -+*(.text.__rmqueue_smallest) -+*(.text.ubi32_eth_napi_poll) -+*(.text.ubi32_pci_write_u32) -+*(.text.ubi32_pci_read_u32) -+*(.text._local_bh_enable) -+*(.text._local_bh_disable) -+*(.text.get_slab) -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/page.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/page.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/page.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/page.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,106 @@ -+/* -+ * arch/ubicom32/include/asm/page.h -+ * Memory page related operations and definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_PAGE_H -+#define _ASM_UBICOM32_PAGE_H -+ -+/* PAGE_SHIFT determines the page size */ -+ -+#define PAGE_SHIFT 12 -+#define PAGE_SIZE (1 << PAGE_SHIFT) -+#define PAGE_MASK (~(PAGE_SIZE-1)) -+ -+#include -+ -+#ifndef __ASSEMBLY__ -+ -+#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) -+#define free_user_page(page, addr) free_page(addr) -+ -+#define clear_page(page) memset((page), 0, PAGE_SIZE) -+#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) -+ -+#define clear_user_page(page, vaddr, pg) clear_page(page) -+#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) -+ -+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \ -+ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr) -+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE -+ -+/* -+ * These are used to make use of C type-checking.. -+ */ -+typedef struct { unsigned long pte; } pte_t; -+typedef struct { unsigned long pmd[16]; } pmd_t; -+typedef struct { unsigned long pgd; } pgd_t; -+typedef struct { unsigned long pgprot; } pgprot_t; -+typedef struct page *pgtable_t; -+ -+#define pte_val(x) ((x).pte) -+#define pmd_val(x) ((&x)->pmd[0]) -+#define pgd_val(x) ((x).pgd) -+#define pgprot_val(x) ((x).pgprot) -+ -+#define __pte(x) ((pte_t) { (x) } ) -+#define __pmd(x) ((pmd_t) { (x) } ) -+#define __pgd(x) ((pgd_t) { (x) } ) -+#define __pgprot(x) ((pgprot_t) { (x) } ) -+ -+extern unsigned long memory_start; -+extern unsigned long memory_end; -+ -+#endif /* !__ASSEMBLY__ */ -+ -+#include -+ -+#define PAGE_OFFSET (PAGE_OFFSET_RAW) -+ -+#ifndef __ASSEMBLY__ -+ -+#define __pa(vaddr) virt_to_phys((void *)(vaddr)) -+#define __va(paddr) phys_to_virt((unsigned long)(paddr)) -+ -+#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -+#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) -+ -+#define virt_to_page(addr) (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) -+#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) -+ -+#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn)) -+#define page_to_pfn(page) virt_to_pfn(page_to_virt(page)) -+#define pfn_valid(pfn) ((pfn) < max_mapnr) -+ -+#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ -+ ((void *)(kaddr) < (void *)memory_end)) -+ -+#endif /* __ASSEMBLY__ */ -+ -+#ifdef __KERNEL__ -+#include -+#endif -+ -+#endif /* _ASM_UBICOM32_PAGE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/page_offset.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/page_offset.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/page_offset.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/page_offset.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,35 @@ -+/* -+ * arch/ubicom32/include/asm/page_offset.h -+ * Definition of PAGE_OFFSET_RAW for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_PAGE_OFFSET_H -+#define _ASM_UBICOM32_PAGE_OFFSET_H -+ -+/* This handles the memory map.. */ -+#define PAGE_OFFSET_RAW 0x3ffc0000 -+ -+#endif /* _ASM_UBICOM32_PAGE_OFFSET_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/param.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/param.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/param.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/param.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,49 @@ -+/* -+ * arch/ubicom32/include/asm/param.h -+ * Definition of miscellaneous constants, including HZ. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_PARAM_H -+#define _ASM_UBICOM32_PARAM_H -+ -+#ifdef __KERNEL__ -+#define HZ CONFIG_HZ -+#define USER_HZ HZ -+#define CLOCKS_PER_SEC (USER_HZ) -+#endif -+ -+#ifndef HZ -+#define HZ 100 -+#endif -+ -+#define EXEC_PAGESIZE 4096 -+ -+#ifndef NOGROUP -+#define NOGROUP (-1) -+#endif -+ -+#define MAXHOSTNAMELEN 64 /* max length of hostname */ -+ -+#endif /* _ASM_UBICOM32_PARAM_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/pci.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/pci.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/pci.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/pci.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,210 @@ -+/* -+ * arch/ubicom32/include/asm/pci.h -+ * Definitions of PCI operations for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_PCI_H -+#define _ASM_UBICOM32_PCI_H -+ -+#include -+ -+/* The PCI address space does equal the physical memory -+ * address space. The networking and block device layers use -+ * this boolean for bounce buffer decisions. -+ */ -+#define PCI_DMA_BUS_IS_PHYS (1) -+ -+ -+ -+/* -+ * Perform a master read/write to the PCI bus. -+ * These functions return a PCI_RESP_xxx code. -+ */ -+extern u8 pci_read_u32(u8 pci_cmd, u32 address, u32 *data); -+extern u8 pci_write_u32(u8 pci_cmd, u32 address, u32 data); -+extern u8 pci_read_u16(u8 pci_cmd, u32 address, u16 *data); -+extern u8 pci_write_u16(u8 pci_cmd, u32 address, u16 data); -+extern u8 pci_read_u8(u8 pci_cmd, u32 address, u8 *data); -+extern u8 pci_write_u8(u8 pci_cmd, u32 address, u8 data); -+ -+ -+#define PCIBIOS_MIN_IO 0x100 -+#define PCIBIOS_MIN_MEM 0x10000000 -+ -+#define pcibios_assign_all_busses() 0 -+#define pcibios_scan_all_fns(a, b) 0 -+extern void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, -+ struct resource *res); -+ -+extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, -+ struct pci_bus_region *region); -+ -+struct pci_sys_data; -+struct pci_bus; -+ -+struct hw_pci { -+ struct list_head buses; -+ int nr_controllers; -+ int (*setup)(int nr, struct pci_sys_data *); -+ struct pci_bus *(*scan)(int nr, struct pci_sys_data *); -+ void (*preinit)(void); -+ void (*postinit)(void); -+ u8 (*swizzle)(struct pci_dev *dev, u8 *pin); -+ int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); -+}; -+ -+/* -+ * Per-controller structure -+ */ -+struct pci_sys_data { -+ struct list_head node; -+ int busnr; /* primary bus number */ -+ u64 mem_offset; /* bus->cpu memory mapping offset */ -+ unsigned long io_offset; /* bus->cpu IO mapping offset */ -+ struct pci_bus *bus; /* PCI bus */ -+ struct resource *resource[3]; /* Primary PCI bus resources */ -+ /* Bridge swizzling */ -+ u8 (*swizzle)(struct pci_dev *, u8 *); -+ /* IRQ mapping */ -+ int (*map_irq)(struct pci_dev *, u8, u8); -+ struct hw_pci *hw; -+}; -+ -+static inline struct resource * -+pcibios_select_root(struct pci_dev *pdev, struct resource *res) -+{ -+ struct resource *root = NULL; -+ -+ if (res->flags & IORESOURCE_IO) -+ root = &ioport_resource; -+ if (res->flags & IORESOURCE_MEM) -+ root = &iomem_resource; -+ -+ return root; -+} -+ -+static inline void pcibios_set_master(struct pci_dev *dev) -+{ -+ /* No special bus mastering setup handling */ -+} -+#define HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE 1 -+#define HAVE_ARCH_PCI_SET_DMA_SEGMENT_BOUNDARY 1 -+ -+#ifdef CONFIG_PCI -+static inline void * pci_alloc_consistent(struct pci_dev *hwdev, size_t size, -+ dma_addr_t *dma_handle) -+{ -+ void *vaddr = kmalloc(size, GFP_KERNEL); -+ if(vaddr != NULL) { -+ *dma_handle = virt_to_phys(vaddr); -+ } -+ return vaddr; -+} -+ -+static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) -+{ -+ return 1; -+} -+ -+static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, -+ void *cpu_addr, dma_addr_t dma_handle) -+{ -+ kfree(cpu_addr); -+ return; -+} -+ -+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, -+ size_t size, int direction) -+{ -+ return virt_to_phys(ptr); -+} -+ -+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, -+ size_t size, int direction) -+{ -+ return; -+} -+ -+static inline dma_addr_t -+pci_map_page(struct pci_dev *hwdev, struct page *page, -+ unsigned long offset, size_t size, int direction) -+{ -+ return pci_map_single(hwdev, page_address(page) + offset, size, (int)direction); -+} -+ -+static inline void -+pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address, -+ size_t size, int direction) -+{ -+ pci_unmap_single(hwdev, dma_address, size, direction); -+} -+ -+static inline int -+pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, -+ int nents, int direction) -+{ -+ return nents; -+} -+ -+static inline void -+pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, -+ int nents, int direction) -+{ -+} -+ -+static inline void -+pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, -+ int nelems, int direction) -+{ -+} -+ -+static inline void -+pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, -+ int nelems, int direction) -+{ -+} -+ -+static inline void -+pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, -+ size_t size, int direction) -+{ -+} -+ -+static inline void -+pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, -+ size_t size, int direction) -+{ -+} -+ -+static inline int -+pci_dma_mapping_error(struct pci_dev *hwdev, dma_addr_t dma_addr) -+{ -+ return dma_addr == 0; -+} -+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); -+extern void pci_iounmap(struct pci_dev *dev, void __iomem *); -+#endif -+ -+#endif /* _ASM_UBICOM32_PCI_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/pcm_tio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/pcm_tio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/pcm_tio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/pcm_tio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,84 @@ -+/* -+ * arch/ubicom32/include/asm/pcm_tio.h -+ * Ubicom32 architecture PCM TIO definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#ifndef _ASM_UBICOM32_PCM_TIO_H -+#define _ASM_UBICOM32_PCM_TIO_H -+ -+#include -+ -+#define PCM_TIO_REGS_VERSION 2 -+struct pcm_tio_regs { -+ /* -+ * set this value to 1 to reload the parameters and restart the HRT -+ */ -+ u32_t reload; -+ -+ /* -+ * Pointers to the input and output buffers -+ */ -+ void *input_buf; -+ void *output_buf; -+ -+ /* -+ * Buffer size (see pcm_hrt.S for constraints) -+ */ -+ u32_t buffer_size; -+ -+ /* -+ * Current cycle. This variable increases every time half the buffer -+ * is consumed. -+ */ -+ u32_t cycle; -+ -+ /* -+ * Fields below this line are not accessed by the HRT. They are purely -+ * informational for the user of this TIO. -+ */ -+ -+ /* -+ * Version of this structure -+ */ -+ u32_t version; -+ -+ /* -+ * Number of channels supported -+ */ -+ u32_t channels; -+ -+ /* -+ * Maximum buffer size -+ */ -+ u32_t max_buffer_size; -+}; -+ -+/* -+ * Our device node -+ */ -+#define PCM_TIO_NODE_VERSION 1 -+struct pcm_tio_node { -+ struct devtree_node dn; -+ u32_t version; -+ struct pcm_tio_regs *regs; -+}; -+ -+#endif -+ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/percpu.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/percpu.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/percpu.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/percpu.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/percpu.h -+ * Generic percpu.h for the Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_PERCPU_H -+#define _ASM_UBICOM32_PERCPU_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_PERCPU_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/pgalloc.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/pgalloc.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/pgalloc.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/pgalloc.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,36 @@ -+/* -+ * arch/ubicom32/include/asm/pgalloc.h -+ * Page table allocation definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_PGALLOC_H -+#define _ASM_UBICOM32_PGALLOC_H -+ -+#include -+#include -+ -+#define check_pgt_cache() do { } while (0) -+ -+#endif /* _ASM_UBICOM32_PGALLOC_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/pgtable.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/pgtable.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/pgtable.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/pgtable.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,124 @@ -+/* -+ * arch/ubicom32/include/asm/pgtable.h -+ * Ubicom32 pseudo page table definitions and operations. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2004 Microtronix Datacom Ltd -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * and various works, Alpha, ix86, M68K, Sparc, ...et al -+ */ -+#ifndef _ASM_UBICOM32_PGTABLE_H -+#define _ASM_UBICOM32_PGTABLE_H -+ -+#include -+ -+//vic - this bit copied from m68knommu version -+#include -+#include -+#include -+ -+typedef pte_t *pte_addr_t; -+ -+#define pgd_present(pgd) (1) /* pages are always present on NO_MM */ -+#define pgd_none(pgd) (0) -+#define pgd_bad(pgd) (0) -+#define pgd_clear(pgdp) -+#define kern_addr_valid(addr) (1) -+#define pmd_offset(a, b) ((void *)0) -+ -+#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */ -+#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */ -+#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */ -+#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */ -+#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */ -+//vic - this bit copied from m68knommu version -+ -+extern void paging_init(void); -+#define swapper_pg_dir ((pgd_t *) 0) -+ -+#define __swp_type(x) (0) -+#define __swp_offset(x) (0) -+#define __swp_entry(typ,off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) -+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -+#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -+ -+/* -+ * pgprot_noncached() is only for infiniband pci support, and a real -+ * implementation for RAM would be more complicated. -+ */ -+#define pgprot_noncached(prot) (prot) -+ -+static inline int pte_file(pte_t pte) { return 0; } -+ -+/* -+ * ZERO_PAGE is a global shared page that is always zero: used -+ * for zero-mapped memory areas etc.. -+ */ -+#define ZERO_PAGE(vaddr) (virt_to_page(0)) -+ -+extern unsigned int kobjsize(const void *objp); -+extern int is_in_rom(unsigned long); -+ -+/* -+ * No page table caches to initialise -+ */ -+#define pgtable_cache_init() do { } while (0) -+ -+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ -+ remap_pfn_range(vma, vaddr, pfn, size, prot) -+ -+extern inline void flush_cache_mm(struct mm_struct *mm) -+{ -+} -+ -+extern inline void flush_cache_range(struct mm_struct *mm, -+ unsigned long start, -+ unsigned long end) -+{ -+} -+ -+/* Push the page at kernel virtual address and clear the icache */ -+extern inline void flush_page_to_ram (unsigned long address) -+{ -+} -+ -+/* Push n pages at kernel virtual address and clear the icache */ -+extern inline void flush_pages_to_ram (unsigned long address, int n) -+{ -+} -+ -+/* -+ * All 32bit addresses are effectively valid for vmalloc... -+ * Sort of meaningless for non-VM targets. -+ */ -+#define VMALLOC_START 0 -+#define VMALLOC_END 0xffffffff -+ -+#define arch_enter_lazy_mmu_mode() do {} while (0) -+#define arch_leave_lazy_mmu_mode() do {} while (0) -+#define arch_flush_lazy_mmu_mode() do {} while (0) -+#define arch_enter_lazy_cpu_mode() do {} while (0) -+#define arch_leave_lazy_cpu_mode() do {} while (0) -+#define arch_flush_lazy_cpu_mode() do {} while (0) -+ -+#endif /* _ASM_UBICOM32_PGTABLE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/plio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/plio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/plio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/plio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,313 @@ -+/* -+ * plio.h -+ * PLIO defines. -+ * -+ * Copyright © 2009 Ubicom Inc. . All Rights Reserved. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can -+ * redistribute it and/or modify it under the terms of the GNU General -+ * Public License as published by the Free Software Foundation, either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ * See the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * This file contains confidential information of Ubicom, Inc. and your use of -+ * this file is subject to the Ubicom Software License Agreement distributed with -+ * this file. If you are uncertain whether you are an authorized user or to report -+ * any unauthorized use, please contact Ubicom, Inc. at +1-408-789-2200. -+ * Unauthorized reproduction or distribution of this file is subject to civil and -+ * criminal penalties. -+ */ -+ -+#ifndef __PLIO__H__ -+#define __PLIO__H__ -+ -+#include -+#include -+ -+#define PLIO_PORT RD -+#define PLIO_EXT_PORT RI -+ -+#define TRANSMIT_FIFO_WATERMARK 8 -+ -+/* -+ * PLIO non-blocking register definitions -+ */ -+#define PLIO_FN 2 -+ -+typedef struct { -+ unsigned : 10; -+ unsigned rxfifo_thread_enable: 1; /* allowed rxfifo thread enable */ -+ unsigned : 1; -+ unsigned rxfifo_thread: 4; /* allowed rxfifo thread access */ -+ unsigned : 4; -+ unsigned br_thread: 4; /* allowed blocking region thread access */ -+ unsigned fn_reset: 4; /* function reset bit vector */ -+ unsigned rxfifo_sel: 1; /* select between RXFIFO 0 and 1 */ -+ unsigned fn_sel: 3; /* select port function */ -+} plio_io_function_t; -+ -+typedef struct { -+ unsigned : 24; -+ unsigned pin:8; -+} plio_gpio_t; -+ -+typedef struct { -+ unsigned : 16; -+ unsigned txfifo_uf: 1; /* TXFIFO underflow */ -+ unsigned txfifo_wm: 1; /* TXFIFO watermark */ -+ unsigned rxfifo_of: 1; /* RXFIFO overflow */ -+ unsigned rxfifo_wm: 1; /* RXFIFO watermark */ -+ unsigned : 5; -+ unsigned lreg_int_addr_rd: 1; /* read from specified LREG address */ -+ unsigned lreg_int_addr_wr: 1; /* write to specified LREG address */ -+ unsigned extctl_int: 4; /* synchronized external interrupts */ -+ unsigned pfsm_int: 1; /* state machine */ -+} plio_intstat_t; -+ -+typedef struct { -+ unsigned txfifo_reset: 1; /* TXFIFO reset for int_set only */ -+ unsigned rxfifo_reset: 1; /* RXFIFO reset for int_set only */ -+ unsigned : 11; -+ unsigned idif_txfifo_flush: 1; /* flush TXFIFO and idif_txfifo */ -+ unsigned idif_rxfifo_flush: 1; /* flush RXFIFO and idif_rxfifo */ -+ unsigned pfsm_start: 1; /* input to fsm */ -+ unsigned txfifo_uf: 1; /* TXFIFO underflow */ -+ unsigned txfifo_wm: 1; /* TXFIFO watermark */ -+ unsigned rxfifo_of: 1; /* RXFIFO overflow */ -+ unsigned rxfifo_wm: 1; /* RXFIFO watermark */ -+ unsigned : 5; -+ unsigned lreg_int_addr_rd: 1; /* read from specified LREG address */ -+ unsigned lreg_int_addr_wr: 1; /* write to specified LREG address */ -+ unsigned extctl_int: 4; /* synchronized external interrupts */ -+ unsigned pfsm_int: 1; /* state machine */ -+} plio_intset_t; -+ -+typedef enum { -+ PLIO_PORT_MODE_D, -+ PLIO_PORT_MODE_DE, -+ PLIO_PORT_MODE_DI, -+ PLIO_PORT_MODE_DEI, -+ PLIO_PORT_MODE_DC, -+} plio_port_mode_t; -+ -+typedef enum { -+ PLIO_CLK_CORE, /* CORE CLK */ -+ PLIO_CLK_IO, /* IO CLK */ -+ PLIO_CLK_EXT, /* EXT CLK */ -+} plio_clk_src_t; -+typedef struct { -+ unsigned : 4; -+ unsigned edif_iaena_sel: 1; /* Input Address Enable Select */ -+ unsigned edif_iaclk_sel: 1; /* Input Address Clock Select */ -+ unsigned edif_iald_inv: 1; /* Input Address Strobe Invert */ -+ unsigned edif_idclk_sel: 1; /* Input Data Clock Select */ -+ unsigned edif_idld_inv: 1; /* Input Data Strobe Invert */ -+ unsigned edif_ds: 3; /* specify IDR and ODR data shift */ -+ unsigned edif_cmp_mode: 1; /* configure IDR comparator output */ -+ unsigned edif_idena_sel: 1; /* Input Data Enable Select */ -+ unsigned ecif_extclk_ena: 1; /* plio_extctl output select */ -+ unsigned idif_tx_fifo_cmd_sel: 1; /* select pfsm_cmd data word position */ -+ unsigned ptif_porti_cfg: 2; /* select port I pin configuration */ -+ unsigned ptif_portd_cfg: 3; /* select port D pin configuration */ -+ plio_port_mode_t ptif_port_mode: 3; /* select other plio ports */ -+ unsigned icif_clk_plio_ext_inv: 1; /* invert external plio clock when set */ -+ unsigned icif_rst_plio: 1; /* reset plio function and io fifos */ -+ plio_clk_src_t icif_clk_src_sel: 2; /* select plio clock source */ -+ unsigned pfsm_prog: 1; /* enable pfsm programming */ -+ unsigned pfsm_cmd: 3; /* software input to pfsm */ -+} plio_fctl0_t; -+ -+typedef struct { -+ unsigned : 2; -+ unsigned idif_byteswap_tx: 3; /* swap TXFIFO byte order */ -+ unsigned idif_byteswap_rx: 3; /* swap RXFIFO byte order */ -+ unsigned : 1; -+ unsigned lreg_ena: 1; /* enable local register map */ -+ unsigned lreg_addr_fifo_cmp_ena: 1; /* enable a specific LREG address from/to TX/RX fifos */ -+ unsigned lreg_addr_fifo_cmp: 5; /* LREG address routed from/to TX/RX fifos */ -+ unsigned : 1; -+ unsigned dcod_iald_idld_sel: 2; /* select address/data strobes */ -+ unsigned dcod_rw_src_sel: 1; /* select LREG strobe source */ -+ unsigned dcod_rd_sel: 5; /* select read strobe source */ -+ unsigned dcod_wr_sel: 5; /* select write strobe source */ -+ unsigned dcod_rd_lvl: 1; /* select active level of read strobe */ -+ unsigned dcod_wr_lvl: 1; /* select active level of read strobe */ -+} plio_fctl1_t; -+ -+typedef struct { -+ unsigned icif_eclk_div: 16; /* external plio clock divider */ -+ unsigned icif_iclk_div: 16; /* internal plio clock divider */ -+} plio_fctl2_t; -+ -+typedef struct { -+ unsigned : 27; -+ unsigned pfsm_state: 5; /* current pfsm state */ -+} plio_stat_0_t; -+ -+typedef struct { -+ unsigned : 3; -+ unsigned lreg_r_int_addr: 5; -+ unsigned : 11; -+ unsigned lreg_w_int_addr: 5; -+ unsigned lreg_w_int_data: 8; -+} plio_stat_1_t; -+ -+typedef struct { -+ unsigned : 32; -+} plio_stat_2_t; -+ -+typedef struct { -+ unsigned tx: 16; -+ unsigned rx: 16; -+} plio_io_fifo_wm_t, plio_io_fifo_lvl_t; -+ -+ -+/* plio blocking region register definitions -+ */ -+typedef struct { -+ unsigned ns1: 5; -+ unsigned ic1: 7; -+ unsigned ec1: 4; -+ unsigned ns0: 5; -+ unsigned ic0: 7; -+ unsigned ec0: 4; -+} plio_sram_t; -+ -+typedef struct { -+ unsigned : 2; -+ unsigned s9: 3; -+ unsigned s8: 3; -+ unsigned s7: 3; -+ unsigned s6: 3; -+ unsigned s5: 3; -+ unsigned s4: 3; -+ unsigned s3: 3; -+ unsigned s2: 3; -+ unsigned s1: 3; -+ unsigned s0: 3; -+} plio_grpsel_t; -+ -+typedef struct { -+ unsigned s7: 4; -+ unsigned s6: 4; -+ unsigned s5: 4; -+ unsigned s4: 4; -+ unsigned s3: 4; -+ unsigned s2: 4; -+ unsigned s1: 4; -+ unsigned s0: 4; -+} plio_cs_lut_t; -+ -+typedef struct { -+ unsigned lut3: 8; -+ unsigned lut2: 8; -+ unsigned lut1: 8; -+ unsigned lut0: 8; -+} plio_extctl_t; -+ -+typedef struct { -+ plio_grpsel_t grpsel[4]; -+ u16_t cv[16]; -+ plio_cs_lut_t cs_lut[4]; -+ plio_extctl_t extctl_o_lut[8]; -+} plio_pfsm_t; -+ -+typedef struct { -+ u32_t odr_oe_sel; -+ u32_t odr_oe; -+ u32_t cmp; -+ u32_t ncmp; -+ u32_t cmp_mask; -+} plio_edif_t; -+ -+typedef enum { -+ PLIO_ECIF_CLK_OUT = 9, -+ PLIO_ECIF_IALD = 9, -+ PLIO_ECIF_CLK_IN = 8, -+ PLIO_ECIF_IDLD = 8, -+ PLIO_ECIF_INT = 2, -+} plio_ecif_output_t; -+ -+typedef struct { -+ u32_t bypass_sync; -+ u32_t ift; -+ u32_t output_type; -+ u32_t output_ena; -+ u32_t output_lvl; -+} plio_ecif_t; -+ -+typedef struct { -+ u32_t idr_addr_pos_mask; -+ u32_t reserved; -+ u32_t lreg_bar; -+} plio_dcod_t; -+ -+typedef struct { -+ u32_t addr_rd_ena; -+ u32_t addr_wr_ena; -+ u32_t addr_rd_int_ena; -+ u32_t addr_wr_int_ena; -+} plio_lcfg_t; -+ -+ -+/* -+ * PLIO configuration -+ */ -+typedef struct { -+ plio_fctl0_t fctl0; -+ plio_fctl1_t fctl1; -+ plio_fctl2_t fctl2; -+} plio_fctl_t; -+ -+typedef struct { -+ plio_pfsm_t pfsm; -+ plio_edif_t edif; -+ plio_ecif_t ecif; -+ plio_dcod_t dcod; -+ plio_lcfg_t lcfg; -+} plio_config_t; -+ -+typedef struct { -+ plio_io_function_t function; -+ plio_gpio_t gpio_ctl; -+ plio_gpio_t gpio_out; -+ plio_gpio_t gpio_in; -+ plio_intstat_t intstat; -+ plio_intstat_t intmask; -+ plio_intset_t intset; -+ plio_intstat_t intclr; -+ unsigned tx_lo; -+ unsigned tx_hi; -+ unsigned rx_lo; -+ unsigned rx_hi; -+ plio_fctl0_t fctl0; -+ plio_fctl1_t fctl1; -+ plio_fctl2_t fctl2; -+ plio_stat_0_t stat0; -+ plio_stat_1_t stat1; -+ plio_stat_2_t stat2; -+ plio_io_fifo_wm_t fifo_wm; -+ plio_io_fifo_lvl_t fifo_lvl; -+} plio_nbr_t; -+ -+typedef struct { -+ u32_t pfsm_sram[256]; -+ plio_config_t config; -+} plio_br_t; -+ -+#define PLIO_NBR ((plio_nbr_t *)(PLIO_PORT)) -+#define PLIO_BR ((plio_br_t *)((PLIO_PORT + IO_PORT_BR_OFFSET))) -+#define PEXT_NBR ((plio_nbr_t *)(PLIO_EXT_PORT)) -+ -+extern void plio_init(const plio_fctl_t *plio_fctl, const plio_config_t *plio_config, const plio_sram_t plio_sram_cfg[], int sram_cfg_size); -+ -+#endif // __PLIO__H__ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/poll.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/poll.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/poll.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/poll.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,36 @@ -+/* -+ * arch/ubicom32/include/asm/poll.h -+ * Ubicom32 specific poll() related flags definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_POLL_H -+#define _ASM_UBICOM32_POLL_H -+ -+#define POLLWRNORM POLLOUT -+#define POLLWRBAND 0x0100 -+ -+#include -+ -+#endif /* _ASM_UBICOM32_POLL_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/posix_types.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/posix_types.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/posix_types.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/posix_types.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,93 @@ -+/* -+ * arch/ubicom32/include/asm/posix_types.h -+ * Ubicom32 architecture posix types. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2004 Microtronix Datacom Ltd -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef __ARCH_UBICOM32_POSIX_TYPES_H -+#define __ARCH_UBICOM32_POSIX_TYPES_H -+ -+/* -+ * This file is generally used by user-level software, so you need to -+ * be a little careful about namespace pollution etc. Also, we cannot -+ * assume GCC is being used. -+ */ -+ -+typedef unsigned long __kernel_ino_t; -+typedef unsigned short __kernel_mode_t; -+typedef unsigned short __kernel_nlink_t; -+typedef long __kernel_off_t; -+typedef int __kernel_pid_t; -+typedef unsigned short __kernel_ipc_pid_t; -+typedef unsigned short __kernel_uid_t; -+typedef unsigned short __kernel_gid_t; -+typedef unsigned int __kernel_size_t; -+typedef int __kernel_ssize_t; -+typedef int __kernel_ptrdiff_t; -+typedef long __kernel_time_t; -+typedef long __kernel_suseconds_t; -+typedef long __kernel_clock_t; -+typedef int __kernel_timer_t; -+typedef int __kernel_clockid_t; -+typedef int __kernel_daddr_t; -+typedef char * __kernel_caddr_t; -+typedef unsigned short __kernel_uid16_t; -+typedef unsigned short __kernel_gid16_t; -+typedef unsigned int __kernel_uid32_t; -+typedef unsigned int __kernel_gid32_t; -+ -+typedef unsigned short __kernel_old_uid_t; -+typedef unsigned short __kernel_old_gid_t; -+typedef unsigned short __kernel_old_dev_t; -+ -+#ifdef __GNUC__ -+typedef long long __kernel_loff_t; -+#endif -+ -+typedef struct { -+#if defined(__KERNEL__) || defined(__USE_ALL) -+ int val[2]; -+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ -+ int __val[2]; -+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ -+} __kernel_fsid_t; -+ -+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) -+ -+#undef __FD_SET -+#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) -+ -+#undef __FD_CLR -+#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) -+ -+#undef __FD_ISSET -+#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) -+ -+#undef __FD_ZERO -+#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) -+ -+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ -+ -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/processor.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/processor.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/processor.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/processor.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,163 @@ -+/* -+ * arch/ubicom32/include/asm/processor.h -+ * Thread related definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1995 Hamish Macdonald -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_PROCESSOR_H -+#define _ASM_UBICOM32_PROCESSOR_H -+ -+/* -+ * Default implementation of macro that returns current -+ * instruction pointer ("program counter"). -+ */ -+#define current_text_addr() ({ __label__ _l; _l: &&_l;}) -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if defined(CONFIG_UBICOM32_V3) -+ #define CPU "IP5K" -+#endif -+#if defined(CONFIG_UBICOM32_V4) -+ #define CPU "IP7K" -+#endif -+#ifndef CPU -+ #define CPU "UNKNOWN" -+#endif -+ -+/* -+ * User space process size: 1st byte beyond user address space. -+ */ -+extern unsigned long memory_end; -+#define TASK_SIZE (memory_end) -+ -+/* -+ * This decides where the kernel will search for a free chunk of vm -+ * space during mmap's. We won't be using it -+ */ -+#define TASK_UNMAPPED_BASE 0 -+ -+/* -+ * This is the structure where we are going to save callee-saved registers. -+ * A5 is the return address, A7 is the stack pointer, A6 is the frame -+ * pointer. This is the frame that is created because of switch_to. This -+ * is not the frame due to interrupt preemption or because of syscall entry. -+ */ -+ -+struct thread_struct { -+ unsigned long d10; /* D10 */ -+ unsigned long d11; /* D11 */ -+ unsigned long d12; /* D12 */ -+ unsigned long d13; /* D13 */ -+ unsigned long a1; /* A1 */ -+ unsigned long a2; /* A2 */ -+ unsigned long a5; /* A5 return address. */ -+ unsigned long a6; /* A6 */ -+ unsigned long sp; /* A7 kernel stack pointer. */ -+}; -+ -+#define INIT_THREAD { \ -+ 0, 0, 0, 0, 0, 0, 0, 0, \ -+ sizeof(init_stack) + (unsigned long) init_stack - 8, \ -+} -+ -+/* -+ * Do necessary setup to start up a newly executed thread. -+ * -+ * pass the data segment into user programs if it exists, -+ * it can't hurt anything as far as I can tell -+ */ -+/* -+ * Do necessary setup to start up a newly executed thread. -+ */ -+#define start_thread(regs, new_pc, new_sp) \ -+ do { \ -+ regs->pc = new_pc & ~3; \ -+ regs->an[5] = new_pc & ~3; \ -+ regs->an[7] = new_sp; \ -+ regs->nesting_level = -1; \ -+ regs->frame_type = UBICOM32_FRAME_TYPE_NEW_THREAD; \ -+ regs->thread_type = NORMAL_THREAD; \ -+ } while(0) -+ -+/* Forward declaration, a strange C thing */ -+struct task_struct; -+ -+/* Free all resources held by a thread. */ -+static inline void release_thread(struct task_struct *dead_task) -+{ -+} -+ -+/* Prepare to copy thread state - unlazy all lazy status */ -+#define prepare_to_copy(tsk) do { } while (0) -+ -+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -+ -+/* -+ * Free current thread data structures etc.. -+ */ -+static inline void exit_thread(void) -+{ -+} -+ -+unsigned long thread_saved_pc(struct task_struct *tsk); -+unsigned long get_wchan(struct task_struct *p); -+ -+#define KSTK_EIP(tsk) (tsk->thread.a5) -+#define KSTK_ESP(tsk) (tsk->thread.sp) -+ -+#define cpu_relax() barrier() -+ -+extern void processor_init(void); -+extern unsigned int processor_timers(void); -+extern unsigned int processor_threads(void); -+extern unsigned int processor_frequency(void); -+extern int processor_interrupts(unsigned int *int0, unsigned int *int1); -+extern void processor_ocm(unsigned long *socm, unsigned long *eocm); -+extern void processor_dram(unsigned long *sdram, unsigned long *edram); -+ -+#define THREAD_SIZE_LONGS (THREAD_SIZE/sizeof(unsigned long)) -+#define KSTK_TOP(info) \ -+({ \ -+ unsigned long *__ptr = (unsigned long *)(info); \ -+ (unsigned long)(&__ptr[THREAD_SIZE_LONGS]); \ -+}) -+ -+#define task_pt_regs(task) \ -+({ \ -+ struct pt_regs *__regs__; \ -+ __regs__ = (struct pt_regs *)(KSTK_TOP(task_stack_page(task))-8); \ -+ __regs__ - 1; \ -+}) -+ -+#endif /* _ASM_UBICOM32_PROCESSOR_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/profilesample.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/profilesample.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/profilesample.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/profilesample.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,44 @@ -+/* -+ * arch/ubicom32/mach-common/profile.h -+ * Private data for the profile module -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ */ -+ -+ -+#ifndef _PROFILESAMPLE_H_ -+#define _PROFILESAMPLE_H_ -+ -+/* -+ * a sample taken by the ipProfile package for sending to the profilertool -+ */ -+struct profile_sample { -+ unsigned int pc; /* PC value */ -+ unsigned int a5; /* a5 contents for parent of leaf function */ -+ unsigned int parent; /* return address from stack, to find the caller */ -+ unsigned int latency; /* CPU clocks since the last message dispatch in this thread (thread 0 ony for now) */ -+ unsigned short active; /* which threads are active - for accurate counting */ -+ unsigned short d_blocked; /* which threads are blocked due to D cache misses */ -+ unsigned short i_blocked; /* which threads are blocked due to I cache misses */ -+ unsigned char cond_codes; /* for branch prediction */ -+ unsigned char thread; /* I-blocked, D-blocked, 4-bit thread number */ -+}; -+ -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ptrace.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ptrace.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ptrace.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ptrace.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,177 @@ -+/* -+ * arch/ubicom32/include/asm/ptrace.h -+ * Ubicom32 architecture ptrace support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_PTRACE_H -+#define _ASM_UBICOM32_PTRACE_H -+ -+#ifndef __ASSEMBLY__ -+ -+/* -+ * We use hard coded constants because this is shared with user -+ * space and the values are NOT allowed to change. Only fields -+ * that are intended to be exposed get values. -+ */ -+#define PT_D0 0 -+#define PT_D1 4 -+#define PT_D2 8 -+#define PT_D3 12 -+#define PT_D4 16 -+#define PT_D5 20 -+#define PT_D6 24 -+#define PT_D7 28 -+#define PT_D8 32 -+#define PT_D9 36 -+#define PT_D10 40 -+#define PT_D11 44 -+#define PT_D12 48 -+#define PT_D13 52 -+#define PT_D14 56 -+#define PT_D15 60 -+#define PT_A0 64 -+#define PT_A1 68 -+#define PT_A2 72 -+#define PT_A3 76 -+#define PT_A4 80 -+#define PT_A5 84 -+#define PT_A6 88 -+#define PT_A7 92 -+#define PT_SP 92 -+#define PT_ACC0HI 96 -+#define PT_ACC0LO 100 -+#define PT_MAC_RC16 104 -+#define PT_ACC1HI 108 -+#define PT_ACC1LO 112 -+#define PT_SOURCE3 116 -+#define PT_INST_CNT 120 -+#define PT_CSR 124 -+#define PT_DUMMY_UNUSED 128 -+#define PT_INT_MASK0 132 -+#define PT_INT_MASK1 136 -+#define PT_TRAP_CAUSE 140 -+#define PT_PC 144 -+#define PT_ORIGINAL_D0 148 -+#define PT_FRAME_TYPE 152 -+ -+/* -+ * The following 'registers' are not registers at all but are used -+ * locate the relocated sections. -+ */ -+#define PT_TEXT_ADDR 200 -+#define PT_TEXT_END_ADDR 204 -+#define PT_DATA_ADDR 208 -+#define PT_EXEC_FDPIC_LOADMAP 212 -+#define PT_INTERP_FDPIC_LOADMAP 216 -+ -+/* -+ * This struct defines the way the registers are stored on the -+ * stack during a system call. -+ */ -+enum thread_type { -+ NORMAL_THREAD, -+ KERNEL_THREAD, -+}; -+ -+#define UBICOM32_FRAME_TYPE_SYSCALL -1 /* System call frame */ -+#define UBICOM32_FRAME_TYPE_INVALID 0 /* Invalid frame, no longer in use */ -+#define UBICOM32_FRAME_TYPE_INTERRUPT 1 /* Interrupt frame */ -+#define UBICOM32_FRAME_TYPE_TRAP 2 /* Trap frame */ -+#define UBICOM32_FRAME_TYPE_SIGTRAMP 3 /* Signal trampoline frame. */ -+#define UBICOM32_FRAME_TYPE_NEW_THREAD 4 /* New Thread. */ -+ -+struct pt_regs { -+ /* -+ * Data Registers -+ */ -+ unsigned long dn[16]; -+ -+ /* -+ * Address Registers -+ */ -+ unsigned long an[8]; -+ -+ /* -+ * Per thread misc registers. -+ */ -+ unsigned long acc0[2]; -+ unsigned long mac_rc16; -+ unsigned long acc1[2]; -+ unsigned long source3; -+ unsigned long inst_cnt; -+ unsigned long csr; -+ unsigned long dummy_unused; -+ unsigned long int_mask0; -+ unsigned long int_mask1; -+ unsigned long trap_cause; -+ unsigned long pc; -+ unsigned long original_dn_0; -+ -+ /* -+ * Frame type. Syscall frames are -1. For other types look above. -+ */ -+ unsigned long frame_type; -+ -+ /* -+ * These fields are not exposed to ptrace. -+ */ -+ unsigned long previous_pc; -+ long nesting_level; /* When the kernel in in user space this -+ * will be -1. */ -+ unsigned long thread_type; /* This indicates if this is a kernel -+ * thread. */ -+}; -+ -+/* -+ * This is the extended stack used by signal handlers and the context -+ * switcher: it's pushed after the normal "struct pt_regs". -+ */ -+struct switch_stack { -+ unsigned long dummy; -+}; -+ -+#ifdef __KERNEL__ -+ -+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ -+#define PTRACE_GETREGS 12 -+#define PTRACE_SETREGS 13 -+ -+#ifndef PS_S -+#define PS_S (0x2000) -+#define PS_M (0x1000) -+#endif -+ -+extern int __user_mode(unsigned long sp); -+ -+#define user_mode(regs) (__user_mode((regs->an[7]))) -+#define user_stack(regs) ((regs)->an[7]) -+#define instruction_pointer(regs) ((regs)->pc) -+#define profile_pc(regs) instruction_pointer(regs) -+extern void show_regs(struct pt_regs *); -+#endif /* __KERNEL__ */ -+ -+#endif /* __ASSEMBLY__ */ -+ -+#endif /* _ASM_UBICOM32_PTRACE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/range-protect-asm.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/range-protect-asm.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/range-protect-asm.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/range-protect-asm.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,91 @@ -+/* -+ * arch/ubicom32/include/asm/range-protect-asm.h -+ * Assembly macros for enabling memory protection. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_RANGE_PROTECT_ASM_H -+#define _ASM_UBICOM32_RANGE_PROTECT_ASM_H -+ -+#if defined(__ASSEMBLY__) -+ -+#include -+ -+/* -+ * You should only use the enable/disable ranges when you have the atomic lock, -+ * if you do not there will be problems. -+ */ -+ -+/* -+ * enable_kernel_ranges -+ * Enable the kernel ranges (disabling protection) for thread, -+ * where thread == (1 << thread number) -+ */ -+.macro enable_kernel_ranges thread -+#ifdef CONFIG_PROTECT_KERNEL -+ or.4 I_RANGE0_EN, I_RANGE0_EN, \thread /* Enable Range Register */ -+ or.4 D_RANGE0_EN, D_RANGE0_EN, \thread -+ or.4 D_RANGE1_EN, D_RANGE1_EN, \thread -+#endif -+.endm -+ -+/* -+ * enable_kernel_ranges_for_current -+ * Enable the kernel ranges (disabling protection) for this thread -+ */ -+.macro enable_kernel_ranges_for_current scratch_reg -+#ifdef CONFIG_PROTECT_KERNEL -+ thread_get_self_mask \scratch_reg -+ enable_kernel_ranges \scratch_reg -+#endif -+.endm -+ -+/* -+ * disable_kernel_ranges -+ * Disables the kernel ranges (enabling protection) for thread -+ * where thread == (1 << thread number) -+ */ -+.macro disable_kernel_ranges thread -+#ifdef CONFIG_PROTECT_KERNEL -+ not.4 \thread, \thread -+ and.4 I_RANGE0_EN, I_RANGE0_EN, \thread /* Disable Range Register */ -+ and.4 D_RANGE0_EN, D_RANGE0_EN, \thread -+ and.4 D_RANGE1_EN, D_RANGE1_EN, \thread -+#endif -+.endm -+ -+/* -+ * disable_kernel_ranges_for_current -+ * Disable kernel ranges (enabling protection) for this thread -+ */ -+.macro disable_kernel_ranges_for_current scratch_reg -+#ifdef CONFIG_PROTECT_KERNEL -+ thread_get_self_mask \scratch_reg -+ disable_kernel_ranges \scratch_reg -+#endif -+.endm -+#endif -+ -+#endif /* _ASM_UBICOM32_RANGE_PROTECT_ASM_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/range-protect.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/range-protect.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/range-protect.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/range-protect.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,62 @@ -+/* -+ * arch/ubicom32/include/asm/range-protect.h -+ * Assembly macros declared in C for enabling memory protection. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_RANGE_PROTECT_H -+#define _ASM_UBICOM32_RANGE_PROTECT_H -+ -+#if !defined(__ASSEMBLY__) -+#include -+/* -+ * The following macros should be the identical to the ones in -+ * range-protect-asm.h -+ * -+ * You should only use the enable/disable ranges when you have the atomic lock, -+ * if you do not there will be problems. -+ */ -+ -+/* -+ * enable_kernel_ranges -+ * Enable the kernel ranges (disabling protection) for thread, -+ * where thread == (1 << thread number) -+ */ -+asm ( -+ ".macro enable_kernel_ranges thread \n\t" -+#ifdef CONFIG_PROTECT_KERNEL -+ " or.4 I_RANGE0_EN, I_RANGE0_EN, \\thread \n\t" /* Enable Range Register */ -+ " or.4 D_RANGE0_EN, D_RANGE0_EN, \\thread \n\t" -+ " or.4 D_RANGE1_EN, D_RANGE1_EN, \\thread \n\t" -+#endif -+ ".endm \n\t" -+); -+ -+#else /* __ASSEMBLY__ */ -+ -+#include -+ -+#endif -+#endif /* _ASM_UBICOM32_RANGE_PROTECT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/resource.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/resource.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/resource.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/resource.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/resource.h -+ * Generic definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_RESOURCE_H -+#define _ASM_UBICOM32_RESOURCE_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_RESOURCE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ring_tio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ring_tio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ring_tio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ring_tio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,42 @@ -+/* -+ * arch/ubicom32/include/asm/ring_tio.h -+ * Ubicom32 architecture Ring TIO definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#ifndef _ASM_UBICOM32_RING_TIO_H -+#define _ASM_UBICOM32_RING_TIO_H -+ -+#include -+ -+#define RING_TIO_NODE_VERSION 2 -+ -+/* -+ * Devtree node for ring -+ */ -+struct ring_tio_node { -+ struct devtree_node dn; -+ -+ u32_t version; -+ void *regs; -+}; -+ -+extern void ring_tio_init(const char *node_name); -+ -+#endif /* _ASM_UBICOM32_RING_TIO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/scatterlist.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/scatterlist.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/scatterlist.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/scatterlist.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,49 @@ -+/* -+ * arch/ubicom32/include/asm/scatterlist.h -+ * Definitions of struct scatterlist for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SCATTERLIST_H -+#define _ASM_UBICOM32_SCATTERLIST_H -+ -+#include -+#include -+ -+struct scatterlist { -+#ifdef CONFIG_DEBUG_SG -+ unsigned long sg_magic; -+#endif -+ unsigned long page_link; -+ unsigned int offset; -+ dma_addr_t dma_address; -+ unsigned int length; -+}; -+ -+#define sg_dma_address(sg) ((sg)->dma_address) -+#define sg_dma_len(sg) ((sg)->length) -+ -+#define ISA_DMA_THRESHOLD (0xffffffff) -+ -+#endif /* _ASM_UBICOM32_SCATTERLIST_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/sd_tio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sd_tio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/sd_tio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sd_tio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,36 @@ -+/* -+ * arch/ubicom32/include/asm/sd_tio.h -+ * SD TIO definitions -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#ifndef _ASM_UBICOM32_SD_TIO_H -+#define _ASM_UBICOM32_SD_TIO_H -+ -+#include -+ -+/* -+ * Devtree node for SD -+ */ -+struct sd_tio_node { -+ struct devtree_node dn; -+ void *regs; -+}; -+ -+#endif /* _ASM_UBICOM32_SD_TIO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/sections.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sections.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/sections.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sections.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/sections.h -+ * Generic sections.h definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SECTIONS_H -+#define _ASM_UBICOM32_SECTIONS_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_SECTIONS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/segment.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/segment.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/segment.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/segment.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,78 @@ -+/* -+ * arch/ubicom32/include/asm/segment.h -+ * Memory segment definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SEGMENT_H -+#define _ASM_UBICOM32_SEGMENT_H -+ -+/* define constants */ -+/* Address spaces (FC0-FC2) */ -+#define USER_DATA (1) -+#ifndef __USER_DS -+#define __USER_DS (USER_DATA) -+#endif -+#define USER_PROGRAM (2) -+#define SUPER_DATA (5) -+#ifndef __KERNEL_DS -+#define __KERNEL_DS (SUPER_DATA) -+#endif -+#define SUPER_PROGRAM (6) -+#define CPU_SPACE (7) -+ -+#ifndef __ASSEMBLY__ -+ -+typedef struct { -+ unsigned long seg; -+} mm_segment_t; -+ -+#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) -+#define USER_DS MAKE_MM_SEG(__USER_DS) -+#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS) -+ -+/* -+ * Get/set the SFC/DFC registers for MOVES instructions -+ */ -+ -+static inline mm_segment_t get_fs(void) -+{ -+ return USER_DS; -+} -+ -+static inline mm_segment_t get_ds(void) -+{ -+ /* return the supervisor data space code */ -+ return KERNEL_DS; -+} -+ -+static inline void set_fs(mm_segment_t val) -+{ -+} -+ -+#define segment_eq(a,b) ((a).seg == (b).seg) -+ -+#endif /* __ASSEMBLY__ */ -+ -+#endif /* _ASM_UBICOM32_SEGMENT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/semaphore.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/semaphore.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/semaphore.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/semaphore.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,140 @@ -+/* -+ * arch/ubicom32/include/asm/semaphore.h -+ * Interrupt-safe semaphores for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * (C) Copyright 1996 Linus Torvalds -+ * m68k version by Andreas Schwab -+ * Copyright (C) 2004 Microtronix Datacom Ltd -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SEMAPHORE_H -+#define _ASM_UBICOM32_SEMAPHORE_H -+ -+#define RW_LOCK_BIAS 0x01000000 -+ -+#ifndef __ASSEMBLY__ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+struct semaphore { -+ atomic_t count; -+ atomic_t waking; -+ wait_queue_head_t wait; -+}; -+ -+#define __SEMAPHORE_INITIALIZER(name, n) \ -+{ \ -+ .count = ATOMIC_INIT(n), \ -+ .waking = ATOMIC_INIT(0), \ -+ .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ -+} -+ -+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ -+ struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) -+ -+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) -+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) -+ -+static inline void sema_init (struct semaphore *sem, int val) -+{ -+ *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); -+} -+ -+static inline void init_MUTEX (struct semaphore *sem) -+{ -+ sema_init(sem, 1); -+} -+ -+static inline void init_MUTEX_LOCKED (struct semaphore *sem) -+{ -+ sema_init(sem, 0); -+} -+ -+asmlinkage void __down_failed(void /* special register calling convention */); -+asmlinkage int __down_failed_interruptible(void /* params in registers */); -+asmlinkage int __down_failed_trylock(void /* params in registers */); -+asmlinkage void __up_wakeup(void /* special register calling convention */); -+ -+asmlinkage void __down(struct semaphore * sem); -+asmlinkage int __down_interruptible(struct semaphore * sem); -+asmlinkage int __down_trylock(struct semaphore * sem); -+asmlinkage void __up(struct semaphore * sem); -+ -+extern spinlock_t semaphore_wake_lock; -+ -+/* -+ * This is ugly, but we want the default case to fall through. -+ * "down_failed" is a special asm handler that calls the C -+ * routine that actually waits. -+ */ -+static inline void down(struct semaphore * sem) -+{ -+ might_sleep(); -+ -+ if (atomic_dec_return(&sem->count) < 0) -+ __down(sem); -+} -+ -+static inline int down_interruptible(struct semaphore * sem) -+{ -+ int ret = 0; -+ -+ -+ might_sleep(); -+ -+ if(atomic_dec_return(&sem->count) < 0) -+ ret = __down_interruptible(sem); -+ return ret; -+} -+ -+static inline int down_trylock(struct semaphore * sem) -+{ -+ int ret = 0; -+ -+ if (atomic_dec_return (&sem->count) < 0) -+ ret = __down_trylock(sem); -+ return ret; -+} -+ -+/* -+ * Note! This is subtle. We jump to wake people up only if -+ * the semaphore was negative (== somebody was waiting on it). -+ * The default case (no contention) will result in NO -+ * jumps for both down() and up(). -+ */ -+static inline void up(struct semaphore * sem) -+{ -+ if (atomic_inc_return(&sem->count) <= 0) -+ __up(sem); -+} -+ -+#endif /* __ASSEMBLY__ */ -+ -+#endif /* _ASM_UBICOM32_SEMAPHORE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/semaphore-helper.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/semaphore-helper.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/semaphore-helper.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/semaphore-helper.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,109 @@ -+/* -+ * arch/ubicom32/include/asm/semaphore-helper.h -+ * Semaphore related definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SEMAPHORE_HELPER_H -+#define _ASM_UBICOM32_SEMAPHORE_HELPER_H -+ -+/* -+ * SMP- and interrupt-safe semaphores helper functions. -+ * -+ * (C) Copyright 1996 Linus Torvalds -+ * -+ * m68k version by Andreas Schwab -+ */ -+ -+ -+/* -+ * These two _must_ execute atomically wrt each other. -+ */ -+static inline void wake_one_more(struct semaphore * sem) -+{ -+ atomic_inc(&sem->waking); -+} -+ -+static inline int waking_non_zero(struct semaphore *sem) -+{ -+ int ret; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&semaphore_wake_lock, flags); -+ ret = 0; -+ if (atomic_read(&sem->waking) > 0) { -+ atomic_dec(&sem->waking); -+ ret = 1; -+ } -+ spin_unlock_irqrestore(&semaphore_wake_lock, flags); -+ return ret; -+} -+ -+/* -+ * waking_non_zero_interruptible: -+ * 1 got the lock -+ * 0 go to sleep -+ * -EINTR interrupted -+ */ -+static inline int waking_non_zero_interruptible(struct semaphore *sem, -+ struct task_struct *tsk) -+{ -+ int ret; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&semaphore_wake_lock, flags); -+ ret = 0; -+ if (atomic_read(&sem->waking) > 0) { -+ atomic_dec(&sem->waking); -+ ret = 1; -+ } else if (signal_pending(tsk)) { -+ atomic_inc(&sem->count); -+ ret = -EINTR; -+ } -+ spin_unlock_irqrestore(&semaphore_wake_lock, flags); -+ return ret; -+} -+ -+/* -+ * waking_non_zero_trylock: -+ * 1 failed to lock -+ * 0 got the lock -+ */ -+static inline int waking_non_zero_trylock(struct semaphore *sem) -+{ -+ int ret; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&semaphore_wake_lock, flags); -+ ret = 1; -+ if (atomic_read(&sem->waking) > 0) { -+ atomic_dec(&sem->waking); -+ ret = 0; -+ } else -+ atomic_inc(&sem->count); -+ spin_unlock_irqrestore(&semaphore_wake_lock, flags); -+ return ret; -+} -+ -+#endif /* _ASM_UBICOM32_SEMAPHORE_HELPER_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/sembuf.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sembuf.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/sembuf.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sembuf.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,52 @@ -+/* -+ * arch/ubicom32/include/asm/sembuf.h -+ * The semid64_ds structure for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SEMBUF_H -+#define _ASM_UBICOM32_SEMBUF_H -+ -+/* -+ * The semid64_ds structure for ubicom32 architecture. -+ * Note extra padding because this structure is passed back and forth -+ * between kernel and user space. -+ * -+ * Pad space is left for: -+ * - 64-bit time_t to solve y2038 problem -+ * - 2 miscellaneous 32-bit values -+ */ -+ -+struct semid64_ds { -+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ -+ __kernel_time_t sem_otime; /* last semop time */ -+ unsigned long __unused1; -+ __kernel_time_t sem_ctime; /* last change time */ -+ unsigned long __unused2; -+ unsigned long sem_nsems; /* no. of semaphores in array */ -+ unsigned long __unused3; -+ unsigned long __unused4; -+}; -+ -+#endif /* _ASM_UBICOM32_SEMBUF_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/setup.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/setup.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/setup.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/setup.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,35 @@ -+/* -+ * arch/ubicom32/include/asm/setup.h -+ * Kernel command line length definition. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2004, Microtronix Datacom Ltd., All rights reserved. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_SETUP_H -+#define _ASM_UBICOM32_SETUP_H -+ -+#define COMMAND_LINE_SIZE 512 -+ -+#endif /* _ASM_UBICOM32_SETUP_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/shmbuf.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/shmbuf.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/shmbuf.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/shmbuf.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,69 @@ -+/* -+ * arch/ubicom32/include/asm/shmbuf.h -+ * The shmid64_ds structure for the Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SHMBUF_H -+#define _ASM_UBICOM32_SHMBUF_H -+ -+/* -+ * The shmid64_ds structure for m68k architecture. -+ * Note extra padding because this structure is passed back and forth -+ * between kernel and user space. -+ * -+ * Pad space is left for: -+ * - 64-bit time_t to solve y2038 problem -+ * - 2 miscellaneous 32-bit values -+ */ -+ -+struct shmid64_ds { -+ struct ipc64_perm shm_perm; /* operation perms */ -+ size_t shm_segsz; /* size of segment (bytes) */ -+ __kernel_time_t shm_atime; /* last attach time */ -+ unsigned long __unused1; -+ __kernel_time_t shm_dtime; /* last detach time */ -+ unsigned long __unused2; -+ __kernel_time_t shm_ctime; /* last change time */ -+ unsigned long __unused3; -+ __kernel_pid_t shm_cpid; /* pid of creator */ -+ __kernel_pid_t shm_lpid; /* pid of last operator */ -+ unsigned long shm_nattch; /* no. of current attaches */ -+ unsigned long __unused4; -+ unsigned long __unused5; -+}; -+ -+struct shminfo64 { -+ unsigned long shmmax; -+ unsigned long shmmin; -+ unsigned long shmmni; -+ unsigned long shmseg; -+ unsigned long shmall; -+ unsigned long __unused1; -+ unsigned long __unused2; -+ unsigned long __unused3; -+ unsigned long __unused4; -+}; -+ -+#endif /* _ASM_UBICOM32_SHMBUF_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/shmparam.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/shmparam.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/shmparam.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/shmparam.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,35 @@ -+/* -+ * arch/ubicom32/include/asm/shmparam.h -+ * Shared memory definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2004 Microtronix Datacom Ltd -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * Alpha, ix86, M68K, Sparc, ...et al -+ */ -+#ifndef _ASM_UBICOM32_SHMPARAM_H -+#define _ASM_UBICOM32_SHMPARAM_H -+ -+#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ -+ -+#endif /* _ASM_UBICOM32_SHMPARAM_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/sigcontext.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sigcontext.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/sigcontext.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sigcontext.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,37 @@ -+/* -+ * arch/ubicom32/include/asm/sigcontext.h -+ * Definition of sigcontext struct for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SIGCONTEXT_H -+#define _ASM_UBICOM32_SIGCONTEXT_H -+ -+#include -+ -+struct sigcontext { -+ struct pt_regs sc_regs; -+}; -+ -+#endif /* _ASM_UBICOM32_SIGCONTEXT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/siginfo.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/siginfo.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/siginfo.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/siginfo.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/siginfo.h -+ * Generic siginfo.h definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SIGINFO_H -+#define _ASM_UBICOM32_SIGINFO_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_SIGINFO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/signal.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/signal.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/signal.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/signal.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,180 @@ -+/* -+ * arch/ubicom32/include/asm/signal.h -+ * Signal related definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SIGNAL_H -+#define _ASM_UBICOM32_SIGNAL_H -+ -+#include -+ -+/* Avoid too many header ordering problems. */ -+struct siginfo; -+ -+#ifdef __KERNEL__ -+/* Most things should be clean enough to redefine this at will, if care -+ is taken to make libc match. */ -+ -+#define _NSIG 64 -+#define _NSIG_BPW 32 -+#define _NSIG_WORDS (_NSIG / _NSIG_BPW) -+ -+typedef unsigned long old_sigset_t; /* at least 32 bits */ -+ -+typedef struct { -+ unsigned long sig[_NSIG_WORDS]; -+} sigset_t; -+ -+#endif /* __KERNEL__ */ -+ -+#define SIGHUP 1 -+#define SIGINT 2 -+#define SIGQUIT 3 -+#define SIGILL 4 -+#define SIGTRAP 5 -+#define SIGABRT 6 -+#define SIGIOT 6 -+#define SIGBUS 7 -+#define SIGFPE 8 -+#define SIGKILL 9 -+#define SIGUSR1 10 -+#define SIGSEGV 11 -+#define SIGUSR2 12 -+#define SIGPIPE 13 -+#define SIGALRM 14 -+#define SIGTERM 15 -+#define SIGSTKFLT 16 -+#define SIGCHLD 17 -+#define SIGCONT 18 -+#define SIGSTOP 19 -+#define SIGTSTP 20 -+#define SIGTTIN 21 -+#define SIGTTOU 22 -+#define SIGURG 23 -+#define SIGXCPU 24 -+#define SIGXFSZ 25 -+#define SIGVTALRM 26 -+#define SIGPROF 27 -+#define SIGWINCH 28 -+#define SIGIO 29 -+#define SIGPOLL SIGIO -+/* -+#define SIGLOST 29 -+*/ -+#define SIGPWR 30 -+#define SIGSYS 31 -+#define SIGUNUSED 31 -+ -+/* These should not be considered constants from userland. */ -+#define SIGRTMIN 32 -+#define SIGRTMAX _NSIG -+ -+/* -+ * SA_FLAGS values: -+ * -+ * SA_ONSTACK indicates that a registered stack_t will be used. -+ * SA_RESTART flag to get restarting signals (which were the default long ago) -+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. -+ * SA_RESETHAND clears the handler when the signal is delivered. -+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. -+ * SA_NODEFER prevents the current signal from being masked in the handler. -+ * -+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single -+ * Unix names RESETHAND and NODEFER respectively. -+ */ -+#define SA_NOCLDSTOP 0x00000001 -+#define SA_NOCLDWAIT 0x00000002 -+#define SA_SIGINFO 0x00000004 -+#define SA_ONSTACK 0x08000000 -+#define SA_RESTART 0x10000000 -+#define SA_NODEFER 0x40000000 -+#define SA_RESETHAND 0x80000000 -+ -+#define SA_NOMASK SA_NODEFER -+#define SA_ONESHOT SA_RESETHAND -+ -+/* -+ * sigaltstack controls -+ */ -+#define SS_ONSTACK 1 -+#define SS_DISABLE 2 -+ -+#define MINSIGSTKSZ 2048 -+#define SIGSTKSZ 8192 -+ -+#include -+ -+#ifdef __KERNEL__ -+struct old_sigaction { -+ __sighandler_t sa_handler; -+ old_sigset_t sa_mask; -+ unsigned long sa_flags; -+ void (*sa_restorer)(void); -+}; -+ -+struct sigaction { -+ __sighandler_t sa_handler; -+ unsigned long sa_flags; -+ void (*sa_restorer)(void); -+ sigset_t sa_mask; /* mask last for extensibility */ -+}; -+ -+struct k_sigaction { -+ struct sigaction sa; -+}; -+#else -+/* Here we must cater to libcs that poke about in kernel headers. */ -+ -+struct sigaction { -+ union { -+ __sighandler_t _sa_handler; -+ void (*_sa_sigaction)(int, struct siginfo *, void *); -+ } _u; -+ sigset_t sa_mask; -+ unsigned long sa_flags; -+ void (*sa_restorer)(void); -+}; -+ -+#define sa_handler _u._sa_handler -+#define sa_sigaction _u._sa_sigaction -+ -+#endif /* __KERNEL__ */ -+ -+typedef struct sigaltstack { -+ void *ss_sp; -+ int ss_flags; -+ size_t ss_size; -+} stack_t; -+ -+#ifdef __KERNEL__ -+ -+#include -+#undef __HAVE_ARCH_SIG_BITOPS -+ -+#define ptrace_signal_deliver(regs, cookie) do { } while (0) -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _ASM_UBICOM32_SIGNAL_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/smp.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/smp.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/smp.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/smp.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,87 @@ -+/* -+ * arch/ubicom32/include/asm/smp.h -+ * SMP definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SMP_H -+#define _ASM_UBICOM32_SMP_H -+ -+#ifndef CONFIG_SMP -+#error you should not include smp.h if smp is off -+#endif -+ -+#ifndef ASSEMBLY -+#include -+#include -+#include -+#include -+ -+typedef unsigned long address_t; -+extern unsigned int smp_ipi_irq; -+ -+/* -+ * This magic constant controls our willingness to transfer -+ * a process across CPUs. -+ * -+ * Such a transfer incurs cache and tlb -+ * misses. The current value is inherited from i386. Still needs -+ * to be tuned for parisc. -+ */ -+#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */ -+#define NO_PROC_ID 0xFF /* No processor magic marker */ -+#define ANY_PROC_ID 0xFF /* Any processor magic marker */ -+ -+#ifdef CONFIG_SMP -+#define raw_smp_processor_id() (current_thread_info()->cpu) -+#endif /* CONFIG_SMP */ -+ -+static inline int __cpu_disable (void) -+{ -+ return 0; -+} -+ -+static inline void __cpu_die (unsigned int cpu) -+{ -+ while(1) { -+ }; -+} -+ -+extern int __cpu_up(unsigned int cpu); -+extern void smp_send_timer_all(void); -+extern void smp_timer_broadcast(const struct cpumask *mask); -+extern void smp_set_affinity(unsigned int irq, const struct cpumask *dest); -+extern void arch_send_call_function_single_ipi(int cpu); -+#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask -+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); -+ -+/* -+ * TODO: Once these are fully tested, we should turn them into -+ * inline macros for performance. -+ */ -+extern unsigned long smp_get_affinity(unsigned int irq, int *all); -+extern void smp_reset_ipi(unsigned long mask); -+ -+#endif /* !ASSEMBLY */ -+#endif /* _ASM_UBICOM32_SMP_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/socket.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/socket.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/socket.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/socket.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,87 @@ -+/* -+ * arch/ubicom32/include/asm/socket.h -+ * Socket options definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SOCKET_H -+#define _ASM_UBICOM32_SOCKET_H -+ -+#include -+ -+/* For setsockopt(2) */ -+#define SOL_SOCKET 1 -+ -+#define SO_DEBUG 1 -+#define SO_REUSEADDR 2 -+#define SO_TYPE 3 -+#define SO_ERROR 4 -+#define SO_DONTROUTE 5 -+#define SO_BROADCAST 6 -+#define SO_SNDBUF 7 -+#define SO_RCVBUF 8 -+#define SO_SNDBUFFORCE 32 -+#define SO_RCVBUFFORCE 33 -+#define SO_KEEPALIVE 9 -+#define SO_OOBINLINE 10 -+#define SO_NO_CHECK 11 -+#define SO_PRIORITY 12 -+#define SO_LINGER 13 -+#define SO_BSDCOMPAT 14 -+/* To add :#define SO_REUSEPORT 15 */ -+#define SO_PASSCRED 16 -+#define SO_PEERCRED 17 -+#define SO_RCVLOWAT 18 -+#define SO_SNDLOWAT 19 -+#define SO_RCVTIMEO 20 -+#define SO_SNDTIMEO 21 -+ -+/* Security levels - as per NRL IPv6 - don't actually do anything */ -+#define SO_SECURITY_AUTHENTICATION 22 -+#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 -+#define SO_SECURITY_ENCRYPTION_NETWORK 24 -+ -+#define SO_BINDTODEVICE 25 -+ -+/* Socket filtering */ -+#define SO_ATTACH_FILTER 26 -+#define SO_DETACH_FILTER 27 -+ -+#define SO_PEERNAME 28 -+#define SO_TIMESTAMP 29 -+#define SCM_TIMESTAMP SO_TIMESTAMP -+ -+#define SO_ACCEPTCONN 30 -+ -+#define SO_PEERSEC 31 -+#define SO_PASSSEC 34 -+#define SO_TIMESTAMPNS 35 -+#define SCM_TIMESTAMPNS SO_TIMESTAMPNS -+ -+#define SO_MARK 36 -+ -+#define SO_TIMESTAMPING 37 -+#define SCM_TIMESTAMPING SO_TIMESTAMPING -+ -+#endif /* _ASM_UBICOM32_SOCKET_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/sockios.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sockios.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/sockios.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/sockios.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,40 @@ -+/* -+ * arch/ubicom32/include/asm/sockios.h -+ * Socket-level ioctl definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SOCKIOS_H -+#define _ASM_UBICOM32_SOCKIOS_H -+ -+/* Socket-level I/O control calls. */ -+#define FIOSETOWN 0x8901 -+#define SIOCSPGRP 0x8902 -+#define FIOGETOWN 0x8903 -+#define SIOCGPGRP 0x8904 -+#define SIOCATMARK 0x8905 -+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ -+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ -+ -+#endif /* _ASM_UBICOM32_SOCKIOS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/spinlock.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/spinlock.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/spinlock.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/spinlock.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,296 @@ -+/* -+ * arch/ubicom32/include/asm/spinlock.h -+ * Spinlock related definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SPINLOCK_H -+#define _ASM_UBICOM32_SPINLOCK_H -+ -+#include -+#include -+#include -+ -+/* -+ * __raw_spin_lock() -+ * Lock the lock. -+ */ -+static inline void __raw_spin_lock(raw_spinlock_t *x) -+{ -+ asm volatile ( -+ "1: bset %0, %0, #0 \n\t" -+ " jmpne.f 1b \n\t" -+ : "+U4" (x->lock) -+ : -+ : "memory", "cc" -+ ); -+} -+ -+/* -+ * __raw_spin_unlock() -+ * Unlock the lock. -+ */ -+static inline void __raw_spin_unlock(raw_spinlock_t *x) -+{ -+ asm volatile ( -+ " bclr %0, %0, #0 \n\t" -+ : "+U4" (x->lock) -+ : -+ : "memory", "cc" -+ ); -+} -+ -+/* -+ * __raw_spin_is_locked() -+ * Test if the lock is locked. -+ */ -+static inline int __raw_spin_is_locked(raw_spinlock_t *x) -+{ -+ return x->lock; -+} -+ -+/* -+ * __raw_spin_unlock_wait() -+ * Wait for the lock to be unlocked. -+ * -+ * Note: the caller has not guarantee that the lock will not -+ * be acquired before they get to it. -+ */ -+static inline void __raw_spin_unlock_wait(raw_spinlock_t *x) -+{ -+ do { -+ cpu_relax(); -+ } while (__raw_spin_is_locked(x)); -+} -+ -+/* -+ * __raw_spin_trylock() -+ * Try the lock, return 0 on failure, 1 on success. -+ */ -+static inline int __raw_spin_trylock(raw_spinlock_t *x) -+{ -+ int ret = 0; -+ -+ asm volatile ( -+ " bset %1, %1, #0 \n\t" -+ " jmpne.f 1f \n\t" -+ " move.4 %0, #1 \n\t" -+ "1: \n\t" -+ : "+r" (ret), "+U4" (x->lock) -+ : -+ : "memory", "cc" -+ ); -+ -+ return ret; -+} -+ -+/* -+ * __raw_spin_lock_flags() -+ * Spin waiting for the lock (enabling IRQ(s)) -+ */ -+static inline void __raw_spin_lock_flags(raw_spinlock_t *x, unsigned long flags) -+{ -+ mb(); -+ while (!__raw_spin_trylock(x)) { -+ /* -+ * If the flags from the IRQ are set, interrupts are disabled and we -+ * need to re-enable them. -+ */ -+ if (!flags) { -+ cpu_relax(); -+ } else { -+ raw_local_irq_enable(); -+ cpu_relax(); -+ raw_local_irq_disable(); -+ } -+ } -+ mb(); -+} -+ -+/* -+ * Read-write spinlocks, allowing multiple readers but only one writer. -+ * Linux rwlocks are unfair to writers; they can be starved for an indefinite -+ * time by readers. With care, they can also be taken in interrupt context. -+ * -+ * In Ubicom32 architecture implementation, we have a spinlock and a counter. -+ * Readers use the lock to serialise their access to the counter (which -+ * records how many readers currently hold the lock). -+ * Writers hold the spinlock, preventing any readers or other writers from -+ * grabbing the rwlock. -+ */ -+ -+/* -+ * __raw_read_lock() -+ * Increment the counter in the rwlock. -+ * -+ * Note that we have to ensure interrupts are disabled in case we're -+ * interrupted by some other code that wants to grab the same read lock -+ */ -+static inline void __raw_read_lock(raw_rwlock_t *rw) -+{ -+ unsigned long flags; -+ raw_local_irq_save(flags); -+ __raw_spin_lock_flags(&rw->lock, flags); -+ rw->counter++; -+ __raw_spin_unlock(&rw->lock); -+ raw_local_irq_restore(flags); -+} -+ -+/* -+ * __raw_read_unlock() -+ * Decrement the counter. -+ * -+ * Note that we have to ensure interrupts are disabled in case we're -+ * interrupted by some other code that wants to grab the same read lock -+ */ -+static inline void __raw_read_unlock(raw_rwlock_t *rw) -+{ -+ unsigned long flags; -+ raw_local_irq_save(flags); -+ __raw_spin_lock_flags(&rw->lock, flags); -+ rw->counter--; -+ __raw_spin_unlock(&rw->lock); -+ raw_local_irq_restore(flags); -+} -+ -+/* -+ * __raw_read_trylock() -+ * Increment the counter if we can. -+ * -+ * Note that we have to ensure interrupts are disabled in case we're -+ * interrupted by some other code that wants to grab the same read lock -+ */ -+static inline int __raw_read_trylock(raw_rwlock_t *rw) -+{ -+ unsigned long flags; -+ retry: -+ raw_local_irq_save(flags); -+ if (__raw_spin_trylock(&rw->lock)) { -+ rw->counter++; -+ __raw_spin_unlock(&rw->lock); -+ raw_local_irq_restore(flags); -+ return 1; -+ } -+ -+ raw_local_irq_restore(flags); -+ -+ /* -+ * If write-locked, we fail to acquire the lock -+ */ -+ if (rw->counter < 0) { -+ return 0; -+ } -+ -+ /* -+ * Wait until we have a realistic chance at the lock -+ */ -+ while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0) { -+ cpu_relax(); -+ } -+ -+ goto retry; -+} -+ -+/* -+ * __raw_write_lock() -+ * -+ * Note that we have to ensure interrupts are disabled in case we're -+ * interrupted by some other code that wants to read_trylock() this lock -+ */ -+static inline void __raw_write_lock(raw_rwlock_t *rw) -+{ -+ unsigned long flags; -+retry: -+ raw_local_irq_save(flags); -+ __raw_spin_lock_flags(&rw->lock, flags); -+ -+ if (rw->counter != 0) { -+ __raw_spin_unlock(&rw->lock); -+ raw_local_irq_restore(flags); -+ -+ while (rw->counter != 0) -+ cpu_relax(); -+ -+ goto retry; -+ } -+ -+ rw->counter = -1; /* mark as write-locked */ -+ mb(); -+ raw_local_irq_restore(flags); -+} -+ -+static inline void __raw_write_unlock(raw_rwlock_t *rw) -+{ -+ rw->counter = 0; -+ __raw_spin_unlock(&rw->lock); -+} -+ -+/* Note that we have to ensure interrupts are disabled in case we're -+ * interrupted by some other code that wants to read_trylock() this lock */ -+static inline int __raw_write_trylock(raw_rwlock_t *rw) -+{ -+ unsigned long flags; -+ int result = 0; -+ -+ raw_local_irq_save(flags); -+ if (__raw_spin_trylock(&rw->lock)) { -+ if (rw->counter == 0) { -+ rw->counter = -1; -+ result = 1; -+ } else { -+ /* Read-locked. Oh well. */ -+ __raw_spin_unlock(&rw->lock); -+ } -+ } -+ raw_local_irq_restore(flags); -+ -+ return result; -+} -+ -+/* -+ * read_can_lock - would read_trylock() succeed? -+ * @lock: the rwlock in question. -+ */ -+static inline int __raw_read_can_lock(raw_rwlock_t *rw) -+{ -+ return rw->counter >= 0; -+} -+ -+/* -+ * write_can_lock - would write_trylock() succeed? -+ * @lock: the rwlock in question. -+ */ -+static inline int __raw_write_can_lock(raw_rwlock_t *rw) -+{ -+ return !rw->counter; -+} -+ -+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) -+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) -+ -+#define _raw_spin_relax(lock) cpu_relax() -+#define _raw_read_relax(lock) cpu_relax() -+#define _raw_write_relax(lock) cpu_relax() -+ -+#endif /* _ASM_UBICOM32_SPINLOCK_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/spinlock_types.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/spinlock_types.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/spinlock_types.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/spinlock_types.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,43 @@ -+/* -+ * arch/ubicom32/include/asm/spinlock_types.h -+ * Spinlock related structure definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SPINLOCK_TYPES_H -+#define _ASM_UBICOM32_SPINLOCK_TYPES_H -+ -+typedef struct { -+ volatile unsigned int lock; -+} raw_spinlock_t; -+ -+typedef struct { -+ raw_spinlock_t lock; -+ volatile int counter; -+} raw_rwlock_t; -+ -+#define __RAW_SPIN_LOCK_UNLOCKED { 0 } -+#define __RAW_RW_LOCK_UNLOCKED { __RAW_SPIN_LOCK_UNLOCKED, 0 } -+ -+#endif /* _ASM_UBICOM32_SPINLOCK_TYPES_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/stacktrace.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/stacktrace.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/stacktrace.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/stacktrace.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,72 @@ -+/* -+ * arch/ubicom32/include/asm/stacktrace.h -+ * Stacktrace functions for the Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_STACKTRACE_H -+#define _ASM_UBICOM32_STACKTRACE_H -+ -+#define between(a, b, c) (( \ -+ ((unsigned long) a) >= ((unsigned long) b)) && \ -+ (((unsigned long)a) <= ((unsigned long)c))) -+ -+/* -+ * These symbols are filled in by the linker. -+ */ -+extern unsigned long _stext; -+extern unsigned long _etext; -+ -+/* OCM text goes from __ocm_text_run_begin to __data_begin */ -+extern unsigned long __ocm_text_run_begin; -+extern unsigned long __data_begin; -+ -+/* Account for OCM case - see stacktrace.c maybe combine(also trap.c) */ -+/* -+ * ubicom32_is_kernel() -+ * -+ * Check to see if the given address belongs to the kernel. -+ * NOMMU does not permit any other means. -+ */ -+static inline int ubicom32_is_kernel(unsigned long addr) -+{ -+ int is_kernel = between(addr, &_stext, &_etext) || \ -+ between(addr, &__ocm_text_run_begin, &__data_begin); -+ -+#ifdef CONFIG_MODULES -+ if (!is_kernel) -+ is_kernel = is_module_address(addr); -+#endif -+ return is_kernel; -+} -+ -+extern unsigned long stacktrace_iterate( -+ unsigned long **trace, -+ unsigned long stext, unsigned long etext, -+ unsigned long ocm_stext, unsigned long ocm_etext, -+ unsigned long sstack, unsigned long estack); -+#ifdef CONFIG_STACKTRACE -+void stacktrace_save_entries(struct task_struct *tsk, struct stack_trace *trace, unsigned long sp); -+#endif -+#endif /* _ASM_UBICOM32_STACKTRACE_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/statfs.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/statfs.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/statfs.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/statfs.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/statfs.h -+ * Generic statfs.h definitions -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_STATFS_H -+#define _ASM_UBICOM32_STATFS_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_STATFS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/stat.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/stat.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/stat.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/stat.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,104 @@ -+/* -+ * arch/ubicom32/include/asm/stat.h -+ * File status definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_STAT_H -+#define _ASM_UBICOM32_STAT_H -+ -+struct __old_kernel_stat { -+ unsigned short st_dev; -+ unsigned short st_ino; -+ unsigned short st_mode; -+ unsigned short st_nlink; -+ unsigned short st_uid; -+ unsigned short st_gid; -+ unsigned short st_rdev; -+ unsigned long st_size; -+ unsigned long st_atime; -+ unsigned long st_mtime; -+ unsigned long st_ctime; -+}; -+ -+struct stat { -+ unsigned short st_dev; -+ unsigned short __pad1; -+ unsigned long st_ino; -+ unsigned short st_mode; -+ unsigned short st_nlink; -+ unsigned short st_uid; -+ unsigned short st_gid; -+ unsigned short st_rdev; -+ unsigned short __pad2; -+ unsigned long st_size; -+ unsigned long st_blksize; -+ unsigned long st_blocks; -+ unsigned long st_atime; -+ unsigned long __unused1; -+ unsigned long st_mtime; -+ unsigned long __unused2; -+ unsigned long st_ctime; -+ unsigned long __unused3; -+ unsigned long __unused4; -+ unsigned long __unused5; -+}; -+ -+/* This matches struct stat64 in glibc2.1, hence the absolutely -+ * insane amounts of padding around dev_t's. -+ */ -+struct stat64 { -+ unsigned long long st_dev; -+ unsigned char __pad1[2]; -+ -+#define STAT64_HAS_BROKEN_ST_INO 1 -+ unsigned long __st_ino; -+ -+ unsigned int st_mode; -+ unsigned int st_nlink; -+ -+ unsigned long st_uid; -+ unsigned long st_gid; -+ -+ unsigned long long st_rdev; -+ unsigned char __pad3[2]; -+ -+ long long st_size; -+ unsigned long st_blksize; -+ -+ unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ -+ -+ unsigned long st_atime; -+ unsigned long st_atime_nsec; -+ -+ unsigned long st_mtime; -+ unsigned long st_mtime_nsec; -+ -+ unsigned long st_ctime; -+ unsigned long st_ctime_nsec; -+ -+ unsigned long long st_ino; -+}; -+ -+#endif /* _ASM_UBICOM32_STAT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/string.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/string.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/string.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/string.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,40 @@ -+/* -+ * arch/ubicom32/include/asm/string.h -+ * String operation definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_STRING_H -+#define _ASM_UBICOM32_STRING_H -+ -+#define __HAVE_ARCH_MEMSET -+extern void *memset(void *b, int c, size_t len); -+ -+#define __HAVE_ARCH_MEMCPY -+extern void *memcpy(void *to, const void *from, size_t len); -+ -+#define __HAVE_ARCH_MEMMOVE -+extern void * memmove(void *to, const void *from, size_t len); -+ -+#endif /* _ASM_UBICOM32_STRING_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/swab.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/swab.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/swab.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/swab.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,45 @@ -+/* -+ * arch/ubicom32/include/asm/byteorder.h -+ * Byte order swapping utility routines. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_BYTEORDER_H -+#define _ASM_UBICOM32_BYTEORDER_H -+ -+#include -+ -+#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) -+# define __BYTEORDER_HAS_U64__ -+# define __SWAB_64_THRU_32__ -+#endif -+ -+#if defined(IP7000) || defined(IP7000_REV2) -+ -+#define __arch__swab16 __builtin_ubicom32_swapb_2 -+#define __arch__swab32 __builtin_ubicom32_swapb_4 -+ -+#endif /* IP7000 */ -+ -+#endif /* _ASM_UBICOM32_BYTEORDER_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/switch-dev.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/switch-dev.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/switch-dev.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/switch-dev.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,51 @@ -+/* -+ * arch/ubicom32/include/asm/switch-dev.h -+ * generic Ethernet switch platform data definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SWITCH_DEV_H -+#define _ASM_UBICOM32_SWITCH_DEV_H -+ -+#define SWITCH_DEV_FLAG_HW_RESET 0x01 -+#define SWITCH_DEV_FLAG_SW_RESET 0x02 -+ -+struct switch_core_platform_data { -+ /* -+ * See flags above -+ */ -+ u32_t flags; -+ -+ /* -+ * GPIO to use for nReset -+ */ -+ int pin_reset; -+ -+ /* -+ * Name of this switch -+ */ -+ const char *name; -+}; -+ -+#endif /* _ASM_UBICOM32_SWITCH_DEV_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/system.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/system.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/system.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/system.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,101 @@ -+/* -+ * arch/ubicom32/include/asm/system.h -+ * Low level switching definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_SYSTEM_H -+#define _ASM_UBICOM32_SYSTEM_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * switch_to(n) should switch tasks to task ptr, first checking that -+ * ptr isn't the current task, in which case it does nothing. -+ */ -+asmlinkage void resume(void); -+extern void *__switch_to(struct task_struct *prev, -+ struct thread_struct *prev_switch, -+ struct thread_struct *next_switch); -+ -+/* -+ * We will need a per linux thread sw_ksp for the switch_to macro to -+ * track the kernel stack pointer for the current thread on that linux thread. -+ */ -+#define switch_to(prev,next,last) \ -+({ \ -+ void *_last; \ -+ _last = (void *) \ -+ __switch_to(prev, &prev->thread, &next->thread); \ -+ (last) = _last; \ -+}) -+ -+/* -+ * Force strict CPU ordering. -+ * Not really required on ubicom32... -+ */ -+#define nop() asm volatile ("nop"::) -+#define mb() asm volatile ("" : : :"memory") -+#define rmb() asm volatile ("" : : :"memory") -+#define wmb() asm volatile ("" : : :"memory") -+#define set_mb(var, value) ({ (var) = (value); wmb(); }) -+ -+#ifdef CONFIG_SMP -+#define smp_mb() mb() -+#define smp_rmb() rmb() -+#define smp_wmb() wmb() -+#define smp_read_barrier_depends() read_barrier_depends() -+#else -+#define smp_mb() mb() -+#define smp_rmb() rmb() -+#define smp_wmb() wmb() -+#define smp_read_barrier_depends() do { } while(0) -+#endif -+ -+#define read_barrier_depends() ((void)0) -+ -+/* -+ * The following defines change how the scheduler calls the switch_to() -+ * macro. -+ * -+ * 1) The first causes the runqueue to be unlocked on entry to -+ * switch_to(). Since our ctx code does not play with the runqueue -+ * we do not need it unlocked. -+ * -+ * 2) The later turns interrupts on during a ctxsw to reduce the latency of -+ * interrupts during ctx. At this point in the port, we believe that this -+ * latency is not a problem since we have very little code to perform a ctxsw. -+ */ -+// #define __ARCH_WANT_UNLOCKED_CTXSW -+// #define __ARCH_WANT_INTERRUPTS_ON_CTXSW -+ -+#endif /* _ASM_UBICOM32_SYSTEM_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/termbits.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/termbits.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/termbits.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/termbits.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,227 @@ -+/* -+ * arch/ubicom32/include/asm/termbits.h -+ * Terminal/serial port definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_TERMBITS_H -+#define _ASM_UBICOM32_TERMBITS_H -+ -+#include -+ -+typedef unsigned char cc_t; -+typedef unsigned int speed_t; -+typedef unsigned int tcflag_t; -+ -+#define NCCS 19 -+struct termios { -+ tcflag_t c_iflag; /* input mode flags */ -+ tcflag_t c_oflag; /* output mode flags */ -+ tcflag_t c_cflag; /* control mode flags */ -+ tcflag_t c_lflag; /* local mode flags */ -+ cc_t c_line; /* line discipline */ -+ cc_t c_cc[NCCS]; /* control characters */ -+}; -+ -+struct termios2 { -+ tcflag_t c_iflag; /* input mode flags */ -+ tcflag_t c_oflag; /* output mode flags */ -+ tcflag_t c_cflag; /* control mode flags */ -+ tcflag_t c_lflag; /* local mode flags */ -+ cc_t c_line; /* line discipline */ -+ cc_t c_cc[NCCS]; /* control characters */ -+ speed_t c_ispeed; /* input speed */ -+ speed_t c_ospeed; /* output speed */ -+}; -+ -+struct ktermios { -+ tcflag_t c_iflag; /* input mode flags */ -+ tcflag_t c_oflag; /* output mode flags */ -+ tcflag_t c_cflag; /* control mode flags */ -+ tcflag_t c_lflag; /* local mode flags */ -+ cc_t c_line; /* line discipline */ -+ cc_t c_cc[NCCS]; /* control characters */ -+ speed_t c_ispeed; /* input speed */ -+ speed_t c_ospeed; /* output speed */ -+}; -+ -+/* c_cc characters */ -+#define VINTR 0 -+#define VQUIT 1 -+#define VERASE 2 -+#define VKILL 3 -+#define VEOF 4 -+#define VTIME 5 -+#define VMIN 6 -+#define VSWTC 7 -+#define VSTART 8 -+#define VSTOP 9 -+#define VSUSP 10 -+#define VEOL 11 -+#define VREPRINT 12 -+#define VDISCARD 13 -+#define VWERASE 14 -+#define VLNEXT 15 -+#define VEOL2 16 -+ -+ -+/* c_iflag bits */ -+#define IGNBRK 0000001 -+#define BRKINT 0000002 -+#define IGNPAR 0000004 -+#define PARMRK 0000010 -+#define INPCK 0000020 -+#define ISTRIP 0000040 -+#define INLCR 0000100 -+#define IGNCR 0000200 -+#define ICRNL 0000400 -+#define IUCLC 0001000 -+#define IXON 0002000 -+#define IXANY 0004000 -+#define IXOFF 0010000 -+#define IMAXBEL 0020000 -+#define IUTF8 0040000 -+ -+/* c_oflag bits */ -+#define OPOST 0000001 -+#define OLCUC 0000002 -+#define ONLCR 0000004 -+#define OCRNL 0000010 -+#define ONOCR 0000020 -+#define ONLRET 0000040 -+#define OFILL 0000100 -+#define OFDEL 0000200 -+#define NLDLY 0000400 -+#define NL0 0000000 -+#define NL1 0000400 -+#define CRDLY 0003000 -+#define CR0 0000000 -+#define CR1 0001000 -+#define CR2 0002000 -+#define CR3 0003000 -+#define TABDLY 0014000 -+#define TAB0 0000000 -+#define TAB1 0004000 -+#define TAB2 0010000 -+#define TAB3 0014000 -+#define XTABS 0014000 -+#define BSDLY 0020000 -+#define BS0 0000000 -+#define BS1 0020000 -+#define VTDLY 0040000 -+#define VT0 0000000 -+#define VT1 0040000 -+#define FFDLY 0100000 -+#define FF0 0000000 -+#define FF1 0100000 -+ -+/* c_cflag bit meaning */ -+#define CBAUD 0010017 -+#define B0 0000000 /* hang up */ -+#define B50 0000001 -+#define B75 0000002 -+#define B110 0000003 -+#define B134 0000004 -+#define B150 0000005 -+#define B200 0000006 -+#define B300 0000007 -+#define B600 0000010 -+#define B1200 0000011 -+#define B1800 0000012 -+#define B2400 0000013 -+#define B4800 0000014 -+#define B9600 0000015 -+#define B19200 0000016 -+#define B38400 0000017 -+#define EXTA B19200 -+#define EXTB B38400 -+#define CSIZE 0000060 -+#define CS5 0000000 -+#define CS6 0000020 -+#define CS7 0000040 -+#define CS8 0000060 -+#define CSTOPB 0000100 -+#define CREAD 0000200 -+#define PARENB 0000400 -+#define PARODD 0001000 -+#define HUPCL 0002000 -+#define CLOCAL 0004000 -+#define CBAUDEX 0010000 -+#define BOTHER 0010000 -+#define B57600 0010001 -+#define B115200 0010002 -+#define B230400 0010003 -+#define B460800 0010004 -+#define B500000 0010005 -+#define B576000 0010006 -+#define B921600 0010007 -+#define B1000000 0010010 -+#define B1152000 0010011 -+#define B1500000 0010012 -+#define B2000000 0010013 -+#define B2500000 0010014 -+#define B3000000 0010015 -+#define B3500000 0010016 -+#define B4000000 0010017 -+#define CIBAUD 002003600000 /* input baud rate */ -+#define CMSPAR 010000000000 /* mark or space (stick) parity */ -+#define CRTSCTS 020000000000 /* flow control */ -+ -+#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ -+ -+/* c_lflag bits */ -+#define ISIG 0000001 -+#define ICANON 0000002 -+#define XCASE 0000004 -+#define ECHO 0000010 -+#define ECHOE 0000020 -+#define ECHOK 0000040 -+#define ECHONL 0000100 -+#define NOFLSH 0000200 -+#define TOSTOP 0000400 -+#define ECHOCTL 0001000 -+#define ECHOPRT 0002000 -+#define ECHOKE 0004000 -+#define FLUSHO 0010000 -+#define PENDIN 0040000 -+#define IEXTEN 0100000 -+ -+ -+/* tcflow() and TCXONC use these */ -+#define TCOOFF 0 -+#define TCOON 1 -+#define TCIOFF 2 -+#define TCION 3 -+ -+/* tcflush() and TCFLSH use these */ -+#define TCIFLUSH 0 -+#define TCOFLUSH 1 -+#define TCIOFLUSH 2 -+ -+/* tcsetattr uses these */ -+#define TCSANOW 0 -+#define TCSADRAIN 1 -+#define TCSAFLUSH 2 -+ -+#endif /* _ASM_UBICOM32_TERMBITS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/termios.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/termios.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/termios.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/termios.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,119 @@ -+/* -+ * arch/ubicom32/include/asm/termios.h -+ * Ubicom32 termio definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_TERMIOS_H -+#define _ASM_UBICOM32_TERMIOS_H -+ -+#include -+#include -+ -+struct winsize { -+ unsigned short ws_row; -+ unsigned short ws_col; -+ unsigned short ws_xpixel; -+ unsigned short ws_ypixel; -+}; -+ -+#define NCC 8 -+struct termio { -+ unsigned short c_iflag; /* input mode flags */ -+ unsigned short c_oflag; /* output mode flags */ -+ unsigned short c_cflag; /* control mode flags */ -+ unsigned short c_lflag; /* local mode flags */ -+ unsigned char c_line; /* line discipline */ -+ unsigned char c_cc[NCC]; /* control characters */ -+}; -+ -+#ifdef __KERNEL__ -+/* intr=^C quit=^| erase=del kill=^U -+ eof=^D vtime=\0 vmin=\1 sxtc=\0 -+ start=^Q stop=^S susp=^Z eol=\0 -+ reprint=^R discard=^U werase=^W lnext=^V -+ eol2=\0 -+*/ -+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" -+#endif -+ -+/* modem lines */ -+#define TIOCM_LE 0x001 -+#define TIOCM_DTR 0x002 -+#define TIOCM_RTS 0x004 -+#define TIOCM_ST 0x008 -+#define TIOCM_SR 0x010 -+#define TIOCM_CTS 0x020 -+#define TIOCM_CAR 0x040 -+#define TIOCM_RNG 0x080 -+#define TIOCM_DSR 0x100 -+#define TIOCM_CD TIOCM_CAR -+#define TIOCM_RI TIOCM_RNG -+#define TIOCM_OUT1 0x2000 -+#define TIOCM_OUT2 0x4000 -+#define TIOCM_LOOP 0x8000 -+ -+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ -+ -+#ifdef __KERNEL__ -+ -+/* -+ * Translate a "termio" structure into a "termios". Ugh. -+ */ -+#define user_termio_to_kernel_termios(termios, termio) \ -+({ \ -+ unsigned short tmp; \ -+ get_user(tmp, &(termio)->c_iflag); \ -+ (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ -+ get_user(tmp, &(termio)->c_oflag); \ -+ (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \ -+ get_user(tmp, &(termio)->c_cflag); \ -+ (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \ -+ get_user(tmp, &(termio)->c_lflag); \ -+ (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ -+ get_user((termios)->c_line, &(termio)->c_line); \ -+ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ -+}) -+ -+/* -+ * Translate a "termios" structure into a "termio". Ugh. -+ */ -+#define kernel_termios_to_user_termio(termio, termios) \ -+({ \ -+ put_user((termios)->c_iflag, &(termio)->c_iflag); \ -+ put_user((termios)->c_oflag, &(termio)->c_oflag); \ -+ put_user((termios)->c_cflag, &(termio)->c_cflag); \ -+ put_user((termios)->c_lflag, &(termio)->c_lflag); \ -+ put_user((termios)->c_line, &(termio)->c_line); \ -+ copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ -+}) -+ -+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2)) -+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2)) -+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) -+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _ASM_UBICOM32_TERMIOS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/thread-asm.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/thread-asm.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/thread-asm.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/thread-asm.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,51 @@ -+/* -+ * arch/ubicom32/include/asm/thread-asm.h -+ * Ubicom32 architecture specific thread definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_THREAD_ASM_H -+#define _ASM_UBICOM32_THREAD_ASM_H -+ -+/* -+ * thread_get_self -+ * Read and shift the current thread into reg -+ * -+ * Note that we don't need to mask the result as bits 6 through 31 of the -+ * ROSR are zeroes. -+ */ -+.macro thread_get_self reg -+ lsr.4 \reg, ROSR, #2 -+.endm -+ -+/* -+ * thread_get_self_mask -+ * Read and shift the current thread mask into reg -+ */ -+.macro thread_get_self_mask reg -+ lsr.4 \reg, ROSR, #2 -+ lsl.4 \reg, #1, \reg /* Thread bit */ -+.endm -+ -+#endif /* _ASM_UBICOM32_THREAD_ASM_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/thread.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/thread.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/thread.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/thread.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,320 @@ -+/* -+ * arch/ubicom32/include/asm/thread.h -+ * Ubicom32 architecture specific thread definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_THREAD_H -+#define _ASM_UBICOM32_THREAD_H -+ -+#if !defined(__ASSEMBLY__) -+ -+#include -+#include -+ -+typedef int thread_t; -+typedef unsigned char thread_type_t; -+typedef void (*thread_exec_fn_t)(void *arg); -+ -+#define THREAD_NULL 0x40 -+#define THREAD_TYPE_HRT (1 << 0) -+#define THREAD_TYPE_SPECIAL 0 -+#define THREAD_TYPE_NORMAL 0 -+#define THREAD_TYPE_BACKGROUND (1 << 1) -+ -+/* -+ * This is the upper bound on the maximum hardware threads that one will find -+ * on a Ubicom processor. It is used to size per hardware thread data structures. -+ */ -+#define THREAD_ARCHITECTURAL_MAX 16 -+ -+/* -+ * TODO: Rename this at some point to be thread_ -+ */ -+extern unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX]; -+ -+ -+/* -+ * thread_get_self() -+ */ -+static inline thread_t thread_get_self(void) -+{ -+ thread_t result; -+ -+ /* -+ * Note that ROSR has zeroes in bits 6 through 31 and so we don't need -+ * to do any additional bit masking here. -+ */ -+ asm ( -+ "lsr.4 %0, ROSR, #2 \n\t" -+ : "=d" (result) -+ : -+ : "cc" -+ ); -+ -+ return result; -+} -+ -+/* -+ * thread_suspend() -+ */ -+static inline void thread_suspend(void) -+{ -+ asm volatile ( -+ "suspend\n\t" -+ : -+ : -+ ); -+} -+ -+/* -+ * thread_resume() -+ */ -+static inline void thread_resume(thread_t thread) -+{ -+ asm volatile ( -+ "move.4 MT_ACTIVE_SET, %0 \n\t" -+ "pipe_flush 0 \n\t" -+ "pipe_flush 0 \n\t" -+ : -+ : "d" (1 << thread) -+ ); -+} -+ -+ -+ -+/* -+ * thread_enable_mask() -+ * Enable all threads in the mask. -+ * -+ * All writes to MT_EN must be protected by the MT_EN_LOCK bit -+ */ -+static inline void thread_enable_mask(unsigned int mask) -+{ -+ /* -+ * must flush the pipeline twice. -+ * first pipe_flush is to ensure write to MT_EN is completed -+ * second one is to ensure any new instructions from -+ * the targeted thread (the one being disabled), that -+ * are issued while the write to MT_EN is being executed, -+ * are completed. -+ */ -+ UBICOM32_LOCK(MT_EN_LOCK_BIT); -+ asm volatile ( -+ "or.4 MT_EN, MT_EN, %0 \n\t" -+ "pipe_flush 0 \n\t" -+ "pipe_flush 0 \n\t" -+ : -+ : "d" (mask) -+ : "cc" -+ ); -+ UBICOM32_UNLOCK(MT_EN_LOCK_BIT); -+} -+ -+/* -+ * thread_enable() -+ */ -+static inline void thread_enable(thread_t thread) -+{ -+ thread_enable_mask(1 << thread); -+} -+ -+/* -+ * thread_disable_mask() -+ * Disable all threads in the mask. -+ * -+ * All writes to MT_EN must be protected by the MT_EN_LOCK bit -+ */ -+static inline void thread_disable_mask(unsigned int mask) -+{ -+ /* -+ * must flush the pipeline twice. -+ * first pipe_flush is to ensure write to MT_EN is completed -+ * second one is to ensure any new instructions from -+ * the targeted thread (the one being disabled), that -+ * are issued while the write to MT_EN is being executed, -+ * are completed. -+ */ -+ UBICOM32_LOCK(MT_EN_LOCK_BIT); -+ asm volatile ( -+ "and.4 MT_EN, MT_EN, %0 \n\t" -+ "pipe_flush 0 \n\t" -+ "pipe_flush 0 \n\t" -+ : -+ : "d" (~mask) -+ : "cc" -+ ); -+ UBICOM32_UNLOCK(MT_EN_LOCK_BIT); -+} -+ -+/* -+ * thread_disable() -+ */ -+static inline void thread_disable(thread_t thread) -+{ -+ thread_disable_mask(1 << thread); -+} -+ -+/* -+ * thread_disable_others() -+ * Disable all other threads -+ */ -+static inline void thread_disable_others(void) -+{ -+ thread_t self = thread_get_self(); -+ thread_disable_mask(~(1 << self)); -+} -+ -+/* -+ * thread_is_trapped() -+ * Is the specified tid trapped? -+ */ -+static inline int thread_is_trapped(thread_t tid) -+{ -+ int thread_mask = (1 << tid); -+ int trap_thread; -+ -+ asm ( -+ "move.4 %0, MT_TRAP \n\t" -+ : "=d" (trap_thread) -+ : -+ ); -+ return (trap_thread & thread_mask); -+} -+ -+/* -+ * thread_is_enabled() -+ * Is the specified tid enabled? -+ */ -+static inline int thread_is_enabled(thread_t tid) -+{ -+ int thread_mask = (1 << tid); -+ int enabled_threads; -+ -+ asm ( -+ "move.4 %0, MT_EN \n\t" -+ : "=d" (enabled_threads) -+ : -+ ); -+ return (enabled_threads & thread_mask); -+} -+ -+/* -+ * thread_get_instruction_count() -+ */ -+static inline unsigned int thread_get_instruction_count(void) -+{ -+ unsigned int result; -+ asm ( -+ "move.4 %0, INST_CNT \n\t" -+ : "=r" (result) -+ ); -+ return result; -+} -+ -+/* -+ * thread_get_pc() -+ * pc could point to a speculative and cancelled instruction unless thread is disabled -+ */ -+static inline void *thread_get_pc(thread_t thread) -+{ -+ void *result; -+ asm ( -+ "move.4 csr, %1 \n\t" -+ "setcsr_flush 0 \n\t" -+ "move.4 %0, pc \n\t" -+ "move.4 csr, #0 \n\t" -+ "setcsr_flush 0 \n\t" -+ : "=r" (result) -+ : "r" ((thread << 9) | (1 << 8)) -+ ); -+ return result; -+} -+ -+/* -+ * thread_get_trap_cause() -+ * This should be called only when the thread is not running -+ */ -+static inline unsigned int thread_get_trap_cause(thread_t thread) -+{ -+ unsigned int result; -+ asm ( -+ "move.4 csr, %1 \n\t" -+ "setcsr_flush 0 \n\t" -+ "move.4 %0, trap_cause \n\t" -+ "move.4 csr, #0 \n\t" -+ "setcsr_flush 0 \n\t" -+ : "=r" (result) -+ : "r" ((thread << 9) | (1 << 8)) -+ ); -+ return result; -+} -+ -+/* -+ * THREAD_STALL macro. -+ */ -+#define THREAD_STALL \ -+ asm volatile ( \ -+ "move.4 mt_dbg_active_clr, #-1 \n\t" \ -+ "pipe_flush 0 \n\t" \ -+ : \ -+ : \ -+ ) -+ -+extern unsigned int thread_get_mainline(void); -+extern void thread_set_mainline(thread_t tid); -+extern thread_t thread_alloc(void); -+extern thread_t thread_start(thread_t thread, thread_exec_fn_t exec, void *arg, unsigned int *sp_high, thread_type_t type); -+ -+/* -+ * asm macros -+ */ -+asm ( -+/* -+ * thread_get_self -+ * Read and shift the current thread into reg -+ * -+ * Note that we don't need to mask the result as bits 6 through 31 of the -+ * ROSR are zeroes. -+ */ -+".macro thread_get_self reg \n\t" -+" lsr.4 \\reg, ROSR, #2 \n\t" -+".endm \n\t" -+ -+/* -+ * thread_get_self_mask -+ * Read and shift the current thread mask into reg -+ */ -+".macro thread_get_self_mask reg \n\t" -+" lsr.4 \\reg, ROSR, #2 \n\t" -+" lsl.4 \\reg, #1, \\reg \n\t" /* Thread bit */ -+".endm \n\t" -+); -+ -+#else /* __ASSEMBLY__ */ -+ -+#include -+ -+#endif /* __ASSEMBLY__ */ -+#endif /* _ASM_UBICOM32_THREAD_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/thread_info.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/thread_info.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/thread_info.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/thread_info.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,134 @@ -+/* -+ * arch/ubicom32/include/asm/thread_info.h -+ * Ubicom32 architecture low-level thread information. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Adapted from the i386 and PPC versions by Greg Ungerer (gerg@snapgear.com) -+ * Copyright (C) 2002 David Howells (dhowells@redhat.com) -+ * - Incorporating suggestions made by Linus Torvalds and Dave Miller -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_THREAD_INFO_H -+#define _ASM_UBICOM32_THREAD_INFO_H -+ -+#include -+ -+/* -+ * Size of kernel stack for each process. This must be a power of 2... -+ */ -+#ifdef CONFIG_4KSTACKS -+#define THREAD_SIZE_ORDER (0) -+#else -+#define THREAD_SIZE_ORDER (1) -+#endif -+ -+/* -+ * for asm files, THREAD_SIZE is now generated by asm-offsets.c -+ */ -+#define THREAD_SIZE (PAGE_SIZE< preemptable, <0 => BUG */ -+ int interrupt_nesting; /* Interrupt nesting level. */ -+ struct restart_block restart_block; -+}; -+ -+/* -+ * macros/functions for gaining access to the thread information structure -+ */ -+#define INIT_THREAD_INFO(tsk) \ -+{ \ -+ .task = &tsk, \ -+ .exec_domain = &default_exec_domain, \ -+ .flags = 0, \ -+ .cpu = 0, \ -+ .interrupt_nesting = 0, \ -+ .restart_block = { \ -+ .fn = do_no_restart_syscall, \ -+ }, \ -+} -+ -+#define init_thread_info (init_thread_union.thread_info) -+#define init_stack (init_thread_union.stack) -+ -+ -+/* how to get the thread information struct from C */ -+static inline struct thread_info *current_thread_info(void) -+{ -+ struct thread_info *ti; -+ -+ asm ( -+ "and.4 %0, sp, %1\n\t" -+ : "=&r" (ti) -+ : "d" (~(THREAD_SIZE-1)) -+ : "cc" -+ ); -+ -+ return ti; -+} -+ -+#define STACK_WARN (THREAD_SIZE / 8) -+ -+#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR 1 -+ -+/* thread information allocation */ -+#define alloc_thread_info(tsk) ((struct thread_info *) \ -+ __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER)) -+#define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_SIZE_ORDER) -+#endif /* __ASSEMBLY__ */ -+ -+#define PREEMPT_ACTIVE 0x4000000 -+ -+/* -+ * thread information flag bit numbers -+ */ -+#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ -+#define TIF_SIGPENDING 1 /* signal pending */ -+#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ -+#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling -+ TIF_NEED_RESCHED */ -+#define TIF_MEMDIE 4 -+ -+/* as above, but as bit values */ -+#define _TIF_SYSCALL_TRACE (1<. -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_TIMEX_H -+#define _ASM_UBICOM32_TIMEX_H -+ -+#define CLOCK_TICK_RATE 266000000 -+ -+// #define ARCH_HAS_READ_CURRENT_TIMER -+ -+typedef unsigned long cycles_t; -+ -+static inline cycles_t get_cycles(void) -+{ -+ return 0; -+} -+ -+extern int timer_alloc(void); -+extern void timer_set(int timervector, unsigned int cycles); -+extern int timer_reset(int timervector, unsigned int cycles); -+extern void timer_tick_init(void); -+extern void timer_device_init(void); -+ -+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) -+extern void local_timer_interrupt(void); -+#endif -+ -+#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) -+extern int local_timer_setup(unsigned int cpu); -+#endif -+ -+#endif /* _ASM_UBICOM32_TIMEX_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/tlbflush.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/tlbflush.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/tlbflush.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/tlbflush.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,79 @@ -+/* -+ * arch/ubicom32/include/asm/tlbflush.h -+ * TLB operations for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2000 Lineo, David McCullough -+ * Copyright (C) 2000-2002, Greg Ungerer -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_TLB_FLUSH_H -+#define _ASM_UBICOM32_TLB_FLUSH_H -+ -+#include -+ -+/* -+ * flush all user-space atc entries. -+ */ -+static inline void __flush_tlb(void) -+{ -+ BUG(); -+} -+ -+static inline void __flush_tlb_one(unsigned long addr) -+{ -+ BUG(); -+} -+ -+#define flush_tlb() __flush_tlb() -+ -+/* -+ * flush all atc entries (both kernel and user-space entries). -+ */ -+static inline void flush_tlb_all(void) -+{ -+ BUG(); -+} -+ -+static inline void flush_tlb_mm(struct mm_struct *mm) -+{ -+ BUG(); -+} -+ -+static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) -+{ -+ BUG(); -+} -+ -+static inline void flush_tlb_range(struct mm_struct *mm, -+ unsigned long start, unsigned long end) -+{ -+ BUG(); -+} -+ -+static inline void flush_tlb_kernel_page(unsigned long addr) -+{ -+ BUG(); -+} -+ -+#endif /* _ASM_UBICOM32_TLB_FLUSH_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/tlb.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/tlb.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/tlb.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/tlb.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,47 @@ -+/* -+ * arch/ubicom32/include/asm/tlb.h -+ * Ubicom32 architecture TLB operations. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_TLB_H -+#define _ASM_UBICOM32_TLB_H -+ -+/* -+ * ubicom32 doesn't need any special per-pte or -+ * per-vma handling.. -+ */ -+#define tlb_start_vma(tlb, vma) do { } while (0) -+#define tlb_end_vma(tlb, vma) do { } while (0) -+#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) -+ -+/* -+ * .. because we flush the whole mm when it -+ * fills up. -+ */ -+#define tlb_flush(tlb) -+ -+#include -+ -+#endif /* _ASM_UBICOM32_TLB_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/topology.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/topology.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/topology.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/topology.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/topology.h -+ * Generic topology.h definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_TOPOLOGY_H -+#define _ASM_UBICOM32_TOPOLOGY_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_TOPOLOGY_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/traps.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/traps.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/traps.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/traps.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,55 @@ -+/* -+ * arch/ubicom32/include/asm/traps.h -+ * Trap related definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_TRAPS_H -+#define _ASM_UBICOM32_TRAPS_H -+ -+/* -+ * Trap causes passed from ultra to Host OS -+ */ -+#define TRAP_CAUSE_TOTAL 13 -+#define TRAP_CAUSE_DST_RANGE_ERR 12 -+#define TRAP_CAUSE_SRC1_RANGE_ERR 11 -+#define TRAP_CAUSE_I_RANGE_ERR 10 -+#define TRAP_CAUSE_DCAPT 9 -+#define TRAP_CAUSE_DST_SERROR 8 -+#define TRAP_CAUSE_SRC1_SERROR 7 -+#define TRAP_CAUSE_DST_MISALIGNED 6 -+#define TRAP_CAUSE_SRC1_MISALIGNED 5 -+#define TRAP_CAUSE_DST_DECODE_ERR 4 -+#define TRAP_CAUSE_SRC1_DECODE_ERR 3 -+#define TRAP_CAUSE_ILLEGAL_INST 2 -+#define TRAP_CAUSE_I_SERROR 1 -+#define TRAP_CAUSE_I_DECODE_ERR 0 -+ -+extern void trap_handler(int irq, struct pt_regs *regs); -+extern void trap_init_interrupt(void); -+extern void unaligned_emulate(unsigned int thread); -+extern int unaligned_only(unsigned int cause); -+ -+#endif /* _ASM_UBICOM32_TRAPS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/types.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/types.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/types.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/types.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,75 @@ -+/* -+ * arch/ubicom32/include/asm/types.h -+ * Date type definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_TYPES_H -+#define _ASM_UBICOM32_TYPES_H -+ -+/* -+ * This file is never included by application software unless -+ * explicitly requested (e.g., via linux/types.h) in which case the -+ * application is Linux specific so (user-) name space pollution is -+ * not a major issue. However, for interoperability, libraries still -+ * need to be careful to avoid a name clashes. -+ */ -+ -+#include -+ -+#ifndef __ASSEMBLY__ -+ -+typedef unsigned short umode_t; -+ -+#endif /* __ASSEMBLY__ */ -+ -+/* -+ * These aren't exported outside the kernel to avoid name space clashes -+ */ -+#ifdef __KERNEL__ -+ -+#define BITS_PER_LONG 32 -+ -+#ifndef __ASSEMBLY__ -+ -+/* DMA addresses are always 32-bits wide */ -+ -+typedef u32 dma_addr_t; -+typedef u32 dma64_addr_t; -+ -+/* -+ * XXX These are "Ubicom style" typedefs. They should be removed in all files used by linux. -+ */ -+typedef u32 u32_t; -+typedef s32 s32_t; -+typedef u16 u16_t; -+typedef s16 s16_t; -+typedef u8 u8_t; -+typedef s8 s8_t; -+ -+#endif /* __ASSEMBLY__ */ -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _ASM_UBICOM32_TYPES_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/uaccess.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/uaccess.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/uaccess.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/uaccess.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,347 @@ -+/* -+ * arch/ubicom32/include/asm/uaccess.h -+ * User space memory access functions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * arch/alpha -+ */ -+#ifndef _ASM_UBICOM32_UACCESS_H -+#define _ASM_UBICOM32_UACCESS_H -+ -+/* -+ * User space memory access functions -+ */ -+#include -+#include -+#include -+ -+#include -+ -+#define VERIFY_READ 0 -+#define VERIFY_WRITE 1 -+ -+/* -+ * The exception table consists of pairs of addresses: the first is the -+ * address of an instruction that is allowed to fault, and the second is -+ * the address at which the program should continue. No registers are -+ * modified, so it is entirely up to the continuation code to figure out -+ * what to do. -+ * -+ * All the routines below use bits of fixup code that are out of line -+ * with the main instruction path. This means when everything is well, -+ * we don't even have to jump over them. Further, they do not intrude -+ * on our cache or tlb entries. -+ */ -+struct exception_table_entry -+{ -+ unsigned long insn, fixup; -+}; -+ -+/* -+ * Ubicom32 does not currently support the exception table handling. -+ */ -+extern unsigned long search_exception_table(unsigned long); -+ -+ -+#if defined(CONFIG_ACCESS_OK_CHECKS_ENABLED) -+extern int __access_ok(unsigned long addr, unsigned long size); -+#else -+static inline int __access_ok(unsigned long addr, unsigned long size) -+{ -+ return 1; -+} -+#endif -+#define access_ok(type, addr, size) \ -+ likely(__access_ok((unsigned long)(addr), (size))) -+ -+/* -+ * The following functions do not exist. They keep callers -+ * of put_user and get_user from passing unsupported argument -+ * types. They result in a link time error. -+ */ -+extern int __put_user_bad(void); -+extern int __get_user_bad(void); -+ -+/* -+ * __put_user_no_check() -+ * Put the requested data into the user space verifying the address -+ * -+ * Careful to not -+ * (a) re-use the arguments for side effects (sizeof/typeof is ok) -+ * (b) require any knowledge of processes at this stage -+ */ -+#define __put_user_no_check(x, ptr, size) \ -+({ \ -+ int __pu_err = 0; \ -+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ -+ switch (size) { \ -+ case 1: \ -+ case 2: \ -+ case 4: \ -+ case 8: \ -+ *__pu_addr = (__typeof__(*(ptr)))x; \ -+ break; \ -+ default: \ -+ __pu_err = __put_user_bad(); \ -+ break; \ -+ } \ -+ __pu_err; \ -+}) -+ -+/* -+ * __put_user_check() -+ * Put the requested data into the user space verifying the address -+ * -+ * Careful to not -+ * (a) re-use the arguments for side effects (sizeof/typeof is ok) -+ * (b) require any knowledge of processes at this stage -+ * -+ * If requested, access_ok() will verify that ptr is a valid user -+ * pointer. -+ */ -+#define __put_user_check(x, ptr, size) \ -+({ \ -+ int __pu_err = -EFAULT; \ -+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ -+ if (access_ok(VERIFY_WRITE, __pu_addr, size)) { \ -+ __pu_err = 0; \ -+ switch (size) { \ -+ case 1: \ -+ case 2: \ -+ case 4: \ -+ case 8: \ -+ *__pu_addr = (__typeof__(*(ptr)))x; \ -+ break; \ -+ default: \ -+ __pu_err = __put_user_bad(); \ -+ break; \ -+ } \ -+ } \ -+ __pu_err; \ -+}) -+ -+/* -+ * __get_user_no_check() -+ * Read the value at ptr into x. -+ * -+ * If requested, access_ok() will verify that ptr is a valid user -+ * pointer. If the caller passes a modifying argument for ptr (e.g. x++) -+ * this macro will not work. -+ */ -+#define __get_user_no_check(x, ptr, size) \ -+({ \ -+ int __gu_err = 0; \ -+ __typeof__((x)) __gu_val = 0; \ -+ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ -+ switch (size) { \ -+ case 1: \ -+ case 2: \ -+ case 4: \ -+ case 8: \ -+ __gu_val = (__typeof__((x)))*(__gu_addr); \ -+ break; \ -+ default: \ -+ __gu_err = __get_user_bad(); \ -+ (x) = 0; \ -+ break; \ -+ } \ -+ (x) = __gu_val; \ -+ __gu_err; \ -+}) -+ -+/* -+ * __get_user_check() -+ * Read the value at ptr into x. -+ * -+ * If requested, access_ok() will verify that ptr is a valid user -+ * pointer. -+ */ -+#define __get_user_check(x, ptr, size) \ -+({ \ -+ int __gu_err = -EFAULT; \ -+ __typeof__(x) __gu_val = 0; \ -+ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ -+ if (access_ok(VERIFY_READ, __gu_addr, size)) { \ -+ __gu_err = 0; \ -+ switch (size) { \ -+ case 1: \ -+ case 2: \ -+ case 4: \ -+ case 8: \ -+ __gu_val = (__typeof__((x)))*(__gu_addr); \ -+ break; \ -+ default: \ -+ __gu_err = __get_user_bad(); \ -+ (x) = 0; \ -+ break; \ -+ } \ -+ } \ -+ (x) = __gu_val; \ -+ __gu_err; \ -+}) -+ -+/* -+ * The "xxx" versions are allowed to perform some amount of address -+ * space checking. See access_ok(). -+ */ -+#define put_user(x,ptr) \ -+ __put_user_check((__typeof__(*(ptr)))(x),(ptr), sizeof(*(ptr))) -+#define get_user(x,ptr) \ -+ __get_user_check((x), (ptr), sizeof(*(ptr))) -+ -+/* -+ * The "__xxx" versions do not do address space checking, useful when -+ * doing multiple accesses to the same area (the programmer has to do the -+ * checks by hand with "access_ok()") -+ */ -+#define __put_user(x,ptr) \ -+ __put_user_no_check((__typeof__(*(ptr)))(x),(ptr), sizeof(*(ptr))) -+#define __get_user(x,ptr) \ -+ __get_user_no_check((x), (ptr), sizeof(*(ptr))) -+ -+/* -+ * __copy_tofrom_user_no_check() -+ * Copy the data either to or from user space. -+ * -+ * Return the number of bytes NOT copied. -+ */ -+static inline unsigned long -+__copy_tofrom_user_no_check(void *to, const void *from, unsigned long n) -+{ -+ memcpy(to, from, n); -+ return 0; -+} -+ -+/* -+ * copy_to_user() -+ * Copy the kernel data to user space. -+ * -+ * Return the number of bytes that were copied. -+ */ -+static inline unsigned long -+copy_to_user(void __user *to, const void *from, unsigned long n) -+{ -+ if (!access_ok(VERIFY_WRITE, to, n)) { -+ return n; -+ } -+ return __copy_tofrom_user_no_check((__force void *)to, from, n); -+} -+ -+/* -+ * copy_from_user() -+ * Copy the user data to kernel space. -+ * -+ * Return the number of bytes that were copied. On error, we zero -+ * out the destination. -+ */ -+static inline unsigned long -+copy_from_user(void *to, const void __user *from, unsigned long n) -+{ -+ if (!access_ok(VERIFY_READ, from, n)) { -+ return n; -+ } -+ return __copy_tofrom_user_no_check(to, (__force void *)from, n); -+} -+ -+#define __copy_to_user(to, from, n) \ -+ __copy_tofrom_user_no_check((__force void *)to, from, n) -+#define __copy_from_user(to, from, n) \ -+ __copy_tofrom_user_no_check(to, (__force void *)from, n) -+#define __copy_to_user_inatomic(to, from, n) \ -+ __copy_tofrom_user_no_check((__force void *)to, from, n) -+#define __copy_from_user_inatomic(to, from, n) \ -+ __copy_tofrom_user_no_check(to, (__force void *)from, n) -+ -+#define copy_to_user_ret(to, from, n, retval) \ -+ ({ if (copy_to_user(to, from, n)) return retval; }) -+ -+#define copy_from_user_ret(to, from, n, retval) \ -+ ({ if (copy_from_user(to, from, n)) return retval; }) -+ -+/* -+ * strncpy_from_user() -+ * Copy a null terminated string from userspace. -+ * -+ * dst - Destination in kernel space. The buffer must be at least count. -+ * src - Address of string in user space. -+ * count - Maximum number of bytes to copy (including the trailing NULL). -+ * -+ * Returns the length of the string (not including the trailing NULL. If -+ * count is smaller than the length of the string, we copy count bytes -+ * and return count. -+ * -+ */ -+static inline long strncpy_from_user(char *dst, const __user char *src, long count) -+{ -+ char *tmp; -+ if (!access_ok(VERIFY_READ, src, 1)) { -+ return -EFAULT; -+ } -+ -+ strncpy(dst, src, count); -+ for (tmp = dst; *tmp && count > 0; tmp++, count--) { -+ ; -+ } -+ return(tmp - dst); -+} -+ -+/* -+ * strnlen_user() -+ * Return the size of a string (including the ending 0) -+ * -+ * Return -EFAULT on exception, a value greater than if too long -+ */ -+static inline long strnlen_user(const __user char *src, long n) -+{ -+ if (!access_ok(VERIFY_READ, src, 1)) { -+ return -EFAULT; -+ } -+ return(strlen(src) + 1); -+} -+ -+#define strlen_user(str) strnlen_user(str, 32767) -+ -+/* -+ * __clear_user() -+ * Zero Userspace -+ */ -+static inline unsigned long __clear_user(__user void *to, unsigned long n) -+{ -+ memset(to, 0, n); -+ return 0; -+} -+ -+/* -+ * clear_user() -+ * Zero user space (check for valid addresses) -+ */ -+static inline unsigned long clear_user(__user void *to, unsigned long n) -+{ -+ if (!access_ok(VERIFY_WRITE, to, n)) { -+ return -EFAULT; -+ } -+ return __clear_user(to, n); -+} -+ -+#endif /* _ASM_UBICOM32_UACCESS_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/uart_tio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/uart_tio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/uart_tio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/uart_tio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,126 @@ -+/* -+ * arch/ubicom32/include/asm/uart_tio.h -+ * Ubicom32 architecture UART TIO definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#ifndef _ASM_UBICOM32_UART_TIO_H -+#define _ASM_UBICOM32_UART_TIO_H -+ -+#include -+ -+#define UARTTIO_RX_FIFO_SIZE 16 -+#define UARTTIO_TX_FIFO_SIZE 16 -+ -+/* -+ * Interrupt flags -+ */ -+#define UARTTIO_UART_INT_RX 0x00000001 // set when a character has been recevied (TODO: add watermark) -+#define UARTTIO_UART_INT_RXOVF 0x00000002 // set when the receive buffer has overflowed -+#define UARTTIO_UART_INT_RXFRAME 0x00000004 // set when there has been a framing error -+ -+#define UARTTIO_UART_INT_TX 0x00000100 // set every time a character is transmitted -+#define UARTTIO_UART_INT_TXBE 0x00000200 // set when the transmit buffer is empty (TODO: add watermark) -+ -+#define UARTTIO_UART_FLAG_ENABLED 0x80000000 -+#define UARTTIO_UART_FLAG_SET_RATE 0x00000001 // set to update baud rate -+#define UARTTIO_UART_FLAG_RESET 0x00000002 // set to reset the port -+struct uarttio_uart { -+ volatile u32_t flags; -+ -+ volatile u32_t baud_rate; -+ volatile u32_t current_baud_rate; -+ u32_t bit_time; -+ -+ /* -+ * Modem status register -+ */ -+ volatile u32_t status; -+ -+ /* -+ * Interrupt registers -+ */ -+ volatile u32_t int_mask; -+ volatile u32_t int_flags; -+ -+ /* -+ * Ports and pins -+ */ -+ u32_t rx_port; -+ u32_t tx_port; -+ -+ u8_t rx_pin; -+ u8_t tx_pin; -+ -+ /* -+ * Configuration Data -+ */ -+ u8_t rx_bits; -+ u8_t rx_stop_bits; -+ u8_t tx_bits; -+ u8_t tx_stop_bits; -+ -+ /* -+ * RX state machine data -+ */ -+ u32_t rx_timer; -+ u32_t rx_bit_pos; -+ u32_t rx_byte; -+ u32_t rx_fifo_head; -+ u32_t rx_fifo_tail; -+ u32_t rx_fifo_size; -+ -+ /* -+ * TX state machine data -+ */ -+ u32_t tx_timer; -+ u32_t tx_bit_pos; -+ u32_t tx_byte; -+ u32_t tx_fifo_head; -+ u32_t tx_fifo_tail; -+ u32_t tx_fifo_size; -+ -+ /* -+ * FIFOs -+ */ -+ u8_t rx_fifo[UARTTIO_RX_FIFO_SIZE]; -+ u8_t tx_fifo[UARTTIO_TX_FIFO_SIZE]; -+}; -+ -+#define UARTTIO_VP_VERSION 1 -+struct uarttio_regs { -+ u32_t version; -+ -+ u32_t thread; -+ -+ u32_t max_uarts; -+ -+ struct uarttio_uart uarts[0]; -+}; -+ -+#define UARTTIO_NODE_VERSION 1 -+struct uarttio_node { -+ struct devtree_node dn; -+ -+ u32_t version; -+ struct uarttio_regs *regs; -+ u32_t regs_sz; -+}; -+ -+#endif /* _ASM_UBICOM32_UART_TIO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubi32-cs4384.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubi32-cs4384.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubi32-cs4384.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubi32-cs4384.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,52 @@ -+/* -+ * arch/ubicom32/include/asm/ubi32-cs4384.h -+ * Ubicom32 architecture CS4384 driver platform data definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#ifndef _ASM_UBICOM32_UBI32_CS4384_H -+#define _ASM_UBICOM32_UBI32_CS4384_H -+ -+enum ubi32_cs4384_mclk_source { -+ UBI32_CS4384_MCLK_PWM_0, -+ UBI32_CS4384_MCLK_PWM_1, -+ UBI32_CS4384_MCLK_PWM_2, -+ UBI32_CS4384_MCLK_CLKDIV_1, -+ UBI32_CS4384_MCLK_OTHER, -+}; -+ -+struct ubi32_cs4384_mclk_entry { -+ /* -+ * Rate, in Hz, of this entry -+ */ -+ int rate; -+ -+ /* -+ * The divider to program to get the rate -+ */ -+ int div; -+}; -+ -+struct ubi32_cs4384_platform_data { -+ enum ubi32_cs4384_mclk_source mclk_src; -+ -+ int n_mclk; -+ struct ubi32_cs4384_mclk_entry *mclk_entries; -+}; -+#endif /* _ASM_UBICOM32_UBI32_CS4384_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubi32-pcm.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubi32-pcm.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubi32-pcm.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubi32-pcm.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,54 @@ -+/* -+ * arch/ubicom32/include/asm/ubi32-pcm.h -+ * Ubicom32 architecture PCM driver platform data definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#ifndef _ASM_UBICOM32_UBI32_PCM_H -+#define _ASM_UBICOM32_UBI32_PCM_H -+ -+/* -+ * This function is called when the sample rate has changed -+ */ -+typedef int (*ubi32_pcm_set_rate_fn_t)(void *appdata, int rate); -+ -+struct ubi32pcm_platform_data { -+ /* -+ * Name of the audio node/inst -+ */ -+ const char *node_name; -+ const char *inst_name; -+ int inst_num; -+ -+ /* -+ * Application specific data provided when calling functions -+ */ -+ void *appdata; -+ -+ /* -+ * Functions called when various things happen -+ */ -+ ubi32_pcm_set_rate_fn_t set_rate; -+ -+ /* -+ * Pointer to optional upper layer data (i.e. DAC config, etc) -+ */ -+ void *priv_data; -+}; -+#endif /* _ASM_UBICOM32_UBI32_PCM_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32bl.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32bl.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32bl.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32bl.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,84 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32bl.h -+ * Ubicom32 architecture backlight driver platform data definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_UBICOM32_BL_H -+#define _ASM_UBICOM32_UBICOM32_BL_H -+ -+/* -+ * Different backlight control mechanisms -+ */ -+enum ubicom32bl_pwm_types { -+ /* -+ * PWM controlled backlight -+ */ -+ UBICOM32BL_TYPE_PWM, -+ -+ /* -+ * HRT based PWM backlight -+ */ -+ UBICOM32BL_TYPE_PWM_HRT, -+ -+ /* -+ * No dimming, just on or off -+ */ -+ UBICOM32BL_TYPE_BINARY, -+}; -+ -+struct ubicom32bl_platform_data { -+ /* -+ * Default intensity of the backlight 0-255 -+ */ -+ u8_t default_intensity; -+ -+ /* -+ * TRUE if the backlight sense is active low. (inverted) -+ * FALSE if the backlight sense is active high. -+ */ -+ bool invert; -+ -+ /* -+ * Type of the backlight -+ */ -+ enum ubicom32bl_pwm_types type; -+ -+ /* -+ * GPIO of the backlight if UBICOM32BL_TYPE_PWM_HRT, UBICOM32BL_TYPE_BINARY -+ */ -+ unsigned gpio; -+ -+ /* -+ * PWM channel and parameters of the backlight if UBICOM32BL_TYPE_PWM -+ * pre_scaler: sets the rate at which the PWM timer is clocked. (clk_core / 2^pre_scaler) -+ * period: sets the period of the timer in timer cycles -+ * The duty cycle will be directly proportional to the brightness setting. -+ */ -+ u32_t pwm_channel; -+ u8_t pwm_prescale; -+ u16_t pwm_period; -+}; -+ -+#endif /* _ASM_UBICOM32_UBICOM32_BL_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32-common-asm.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32-common-asm.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32-common-asm.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32-common-asm.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,49 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32-common-asm.h -+ * Ubicom32 atomic lock operations. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_UBICOM32_COMMON_ASM_H -+#define _ASM_UBICOM32_UBICOM32_COMMON_ASM_H -+ -+/* -+ * atomic_lock_acquire macro -+ * Equivalent to __atomic_lock_acquire() -+ */ -+.macro atomic_lock_acquire -+ bset scratchpad1, scratchpad1, #ATOMIC_LOCK_BIT -+ jmpne.f .-4 -+.endm -+ -+/* -+ * atomic_lock_release macro -+ * Equivalent to __atomic_lock_release() -+ */ -+.macro atomic_lock_release -+ bclr scratchpad1, scratchpad1, #ATOMIC_LOCK_BIT -+.endm -+ -+#endif /* _ASM_UBICOM32_UBICOM32_COMMON_ASM_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32-common.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32-common.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32-common.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32-common.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,128 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32-common.h -+ * Ubicom32 atomic lock operations. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_UBICOM32_COMMON_H -+#define _ASM_UBICOM32_UBICOM32_COMMON_H -+ -+#define S(arg) #arg -+#define D(arg) S(arg) -+/* -+ * scratchpad1 is owned by the LDSR. -+ * -+ * The upper bits provide 16 global spinlocks. Acquiring one of these -+ * global spinlocks synchornizes across multiple threads and prevents -+ * the LDSR from delivering any interrupts while the lock is held. -+ * Use these locks only when absolutely required. -+ * -+ * The lower 16 bits of scratchpad1 are used as per thread interrupt -+ * enable/disable bits. These bits will prevent a thread from receiving -+ * any interrupts. -+ * -+ * Bit Usage: -+ * - MT_EN_LOCK_BIT - Protects writes to MT_EN, so code can read current value -+ * then write a new value atomically (profiler for example) -+ * - ATOMIC_LOCK_BIT - Used to provide general purpose atomic handling. -+ * - LDSR_LOCK_BIT - Used by the LDSR exclusively to provide protection. -+ * - DCCR_LOCK_BIT - Used to limit access to the DCCR cache control peripheral -+ * - ICCR_LOCK_BIT - Used to limit access to the ICCR cache control peripheral -+ * - LSB 16 bits - Used by the LDSR to represent thread enable/disable bits. -+ */ -+#define MT_EN_LOCK_BIT 31 -+#define ATOMIC_LOCK_BIT 30 -+#define LDSR_LOCK_BIT 29 -+#define PCI_LOCK_BIT 28 -+#define ICCR_LOCK_BIT 27 -+#define DCCR_LOCK_BIT 26 -+ -+#if !defined(__ASSEMBLY__) -+ -+#define UBICOM32_TRYLOCK(bit) \ -+ asm volatile ( \ -+ " move.4 %0, #0 \n\t" \ -+ " bset scratchpad1, scratchpad1, #"D(bit)" \n\t" \ -+ " jmpne.f 1f \n\t" \ -+ " move.4 %0, #1 \n\t" \ -+ "1: \n\t" \ -+ : "=r" (ret) \ -+ : \ -+ : "cc", "memory" \ -+ ) \ -+ -+#define UBICOM32_UNLOCK(bit) \ -+ asm volatile ( \ -+ " bclr scratchpad1, scratchpad1, #"D(bit)" \n\t" \ -+ : \ -+ : \ -+ : "cc", "memory" \ -+ ) \ -+ -+#define UBICOM32_LOCK(bit) \ -+ asm volatile ( \ -+ "1: bset scratchpad1, scratchpad1, #"D(bit)" \n\t" \ -+ " jmpne.f 1b \n\t" \ -+ : \ -+ : \ -+ : "cc", "memory" \ -+ ) \ -+ -+/* -+ * __atomic_lock_trylock() -+ * Attempt to acquire the lock, return TRUE if acquired. -+ */ -+static inline int __atomic_lock_trylock(void) -+{ -+ int ret; -+ UBICOM32_TRYLOCK(ATOMIC_LOCK_BIT); -+ return ret; -+} -+ -+/* -+ * __atomic_lock_release() -+ * Release the global atomic lock. -+ * -+ * Note: no one is suspended waiting since this lock is a spinning lock. -+ */ -+static inline void __atomic_lock_release(void) -+{ -+ UBICOM32_UNLOCK(ATOMIC_LOCK_BIT); -+} -+ -+/* -+ * __atomic_lock_acquire() -+ * Acquire the global atomic lock, spin if not available. -+ */ -+static inline void __atomic_lock_acquire(void) -+{ -+ UBICOM32_LOCK(ATOMIC_LOCK_BIT); -+} -+#else /* __ASSEMBLY__ */ -+ -+#include -+ -+#endif /* __ASSEMBLY__ */ -+#endif /* _ASM_UBICOM32_UBICOM32_COMMON_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32fb.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32fb.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32fb.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32fb.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,56 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32fb.h -+ * Ubicom32 architecture video frame buffer definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#ifndef _ASM_UBICOM32_UBICOM32FB_H -+#define _ASM_UBICOM32_UBICOM32FB_H -+ -+#include -+ -+/* -+ * Set next frame -+ */ -+#define UBICOM32FB_IOCTL_SET_NEXT_FRAME _IOW('r', 1, void *) -+#define UBICOM32FB_IOCTL_SET_NEXT_FRAME_SYNC _IOW('r', 2, void *) -+ -+/* -+ * Set Mode -+ */ -+#define UBICOM32FB_IOCTL_SET_MODE _IOW('r', 3, void *) -+struct ubicom32fb_mode { -+ unsigned long width; -+ unsigned long height; -+ unsigned long flags; -+ void *next_frame; -+}; -+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_SCAN_ORDER (1 << 8) -+ -+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_BLOCK_ORDER (1 << 7) -+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV (1 << 6) -+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VSUB (1 << 5) -+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_16_255 (1 << 4) -+ -+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_0_255 (1 << 3) -+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_2_1 (1 << 2) -+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_1_1 (1 << 1) -+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_SCALE_ENABLE (1 << 0) -+ -+#endif /* _ASM_UBICOM32_UBICOM32FB_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32hid.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32hid.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32hid.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32hid.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,133 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32hid.h -+ * Ubicom32 architecture HID driver platform data definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_UBICOM32_HID_H -+#define _ASM_UBICOM32_UBICOM32_HID_H -+ -+enum ubicom32hid_bl_types { -+ /* -+ * On or off, using command SET_BL_EN, PB4 -+ */ -+ UBICOM32HID_BL_TYPE_BINARY, -+ -+ /* -+ * Dimmable, using command SET_PWM, PB3 -+ */ -+ UBICOM32HID_BL_TYPE_PWM, -+}; -+ -+/* -+ * IR code mapping to event code. -+ * If there are no button mappings and no ir mappings -+ * then no input driver will be registered. -+ */ -+struct ubicom32hid_ir { -+ /* -+ * Input event code (KEY_*, SW_*, etc) -+ */ -+ int code; -+ -+ /* -+ * Input event type (EV_KEY, EV_SW, etc) -+ */ -+ int type; -+ -+ /* -+ * The IR code of this button. -+ */ -+ uint32_t ir_code; -+}; -+ -+/* -+ * Button mapping to event code. -+ * If there are no button mappings and no ir mappings -+ * then no input driver will be registered. -+ */ -+struct ubicom32hid_button { -+ /* -+ * Input event code (KEY_*, SW_*, etc) -+ */ -+ int code; -+ -+ /* -+ * Input event type (EV_KEY, EV_SW, etc) -+ */ -+ int type; -+ -+ /* -+ * Bit number of this button. -+ */ -+ uint8_t bit; -+}; -+ -+struct ubicom32hid_platform_data { -+ /* -+ * Default intensity of the backlight 0-255 -+ */ -+ u8_t default_intensity; -+ -+ /* -+ * GPIO number of the reset line and its polarity. -+ */ -+ unsigned gpio_reset; -+ int gpio_reset_polarity; -+ -+ /* -+ * TRUE if the backlight sense is active low. (inverted) -+ * FALSE if the backlight sense is active high. -+ */ -+ bool invert; -+ -+ /* -+ * Type of the backlight we are controlling -+ */ -+ enum ubicom32hid_bl_types type; -+ -+ /* -+ * Optional polling rate for input, in ms, defaults to 100ms -+ */ -+ int poll_interval; -+ -+ /* -+ * Optional name to register as input device -+ */ -+ const char *input_name; -+ -+ /* -+ * Button mapping array -+ */ -+ const struct ubicom32hid_button *buttons; -+ int nbuttons; -+ -+ /* -+ * IR mapping array -+ */ -+ const struct ubicom32hid_ir *ircodes; -+ int nircodes; -+}; -+ -+#endif /* _ASM_UBICOM32_UBICOM32_HID_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32input.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32input.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32input.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32input.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,76 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32input.h -+ * Ubicom32 Input driver, based on gpio-keys -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * -+ * TODO: add groups for inputs which can be sampled together -+ */ -+ -+#ifndef _ASM_UBICOM32_UBICOM32_INPUT_H -+#define _ASM_UBICOM32_UBICOM32_INPUT_H -+ -+struct ubicom32input_button { -+ /* -+ * Input event code (KEY_*, SW_*, etc) -+ */ -+ int code; -+ -+ /* -+ * Input event type (EV_KEY, EV_SW, etc) -+ */ -+ int type; -+ -+ /* -+ * GPIO to poll -+ */ -+ int gpio; -+ -+ /* -+ * 1 for active low, 0 for active high -+ */ -+ int active_low; -+ -+ /* -+ * Description, used for reserving GPIOs -+ */ -+ const char *desc; -+}; -+ -+struct ubicom32input_platform_data { -+ struct ubicom32input_button *buttons; -+ int nbuttons; -+ -+ /* -+ * Optional poll interval, in ms, defaults to 50ms -+ */ -+ int poll_interval; -+ -+ /* -+ * Option Name of this driver -+ */ -+ const char *name; -+}; -+ -+#endif /* _ASM_UBICOM32_UBICOM32_INPUT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32input_i2c.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32input_i2c.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32input_i2c.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32input_i2c.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,71 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32input_i2c.h -+ * Ubicom32 architecture Input driver over I2C platform data definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * -+ * TODO: add groups for inputs which can be sampled together -+ */ -+ -+#ifndef _ASM_UBICOM32_UBICOM32_INPUT_I2C_H -+#define _ASM_UBICOM32_UBICOM32_INPUT_I2C_H -+ -+struct ubicom32input_i2c_button { -+ /* -+ * Input event code (KEY_*, SW_*, etc) -+ */ -+ int code; -+ -+ /* -+ * Input event type (EV_KEY, EV_SW, etc) -+ */ -+ int type; -+ -+ /* -+ * Bit number of this button. (0 - ngpio) -+ */ -+ int bit; -+ -+ /* -+ * 1 for active low, 0 for active high -+ */ -+ int active_low; -+}; -+ -+struct ubicom32input_i2c_platform_data { -+ struct ubicom32input_i2c_button *buttons; -+ int nbuttons; -+ -+ /* -+ * Optional poll interval, in ms, defaults to 100ms -+ */ -+ int poll_interval; -+ -+ /* -+ * Option Name of this driver -+ */ -+ const char *name; -+}; -+ -+#endif /* _ASM_UBICOM32_UBICOM32_INPUT_I2C_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32lcd.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32lcd.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32lcd.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32lcd.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,38 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32lcd.h -+ * Ubicom32 architecture LCD driver platform data definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#ifndef _ASM_UBICOM32_UBICOM32_LCD_H -+#define _ASM_UBICOM32_UBICOM32_LCD_H -+ -+#include -+ -+struct ubicom32lcd_platform_data { -+ int pin_cs; -+ int pin_rs; -+ int pin_rd; -+ int pin_wr; -+ int pin_reset; -+ int data_shift; -+ struct ubicom32_io_port *port_data; -+}; -+ -+#endif /* _ASM_UBICOM32_UBICOM32_LCD_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32lcdpower.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32lcdpower.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32lcdpower.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32lcdpower.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,39 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32lcdpower.h -+ * Ubicom32 architecture LCD driver platform data definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_UBICOM32_LCDPOWER_H -+#define _ASM_UBICOM32_UBICOM32_LCDPOWER_H -+ -+struct ubicom32lcdpower_platform_data { -+ /* -+ * GPIO and polarity for VGH signal. A FALSE polarity is active low, TRUE is active high. -+ */ -+ int vgh_gpio; -+ bool vgh_polarity; -+}; -+ -+#endif /* _ASM_UBICOM32_UBICOM32_LCDPOWER_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32ring.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32ring.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32ring.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32ring.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,103 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32ring.h -+ * Userspace I/O platform driver for Ubicom32 ring buffers -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#ifndef _ASM_UBICOM32_UBICOM32RING_H -+#define _ASM_UBICOM32_UBICOM32RING_H -+ -+#define UIO_UBICOM32RING_REG_VERSION 2 -+ -+struct uio_ubicom32ring_desc { -+ volatile unsigned int head; -+ volatile unsigned int tail; -+ unsigned int entries; -+ volatile unsigned int ring[0]; -+}; -+ -+struct uio_ubicom32ring_regs { -+ unsigned int version; -+ -+ /* -+ * Magic type used to identify the ring set. Each driver will -+ * have a different magic value. -+ */ -+ unsigned int magic; -+ -+ /* -+ * Registers defined by the driver -+ */ -+ unsigned int regs_size; -+ void *regs; -+ -+ /* -+ * The locations of the rings -+ * -+ * DO NOT ADD ANYTHING BELOW THIS LINE -+ */ -+ unsigned int num_rings; -+ struct uio_ubicom32ring_desc *rings[0]; -+}; -+ -+/* -+ * ringtio_ring_flush -+ */ -+static inline void ringtio_ring_flush(struct uio_ubicom32ring_desc *rd) -+{ -+ rd->head = rd->tail = 0; -+} -+ -+/* -+ * ringtio_ring_get -+ */ -+static inline int ringtio_ring_get(struct uio_ubicom32ring_desc *rd, void **val) -+{ -+ if (rd->head == rd->tail) { -+ return 0; -+ } -+ -+ *val = (void *)rd->ring[rd->head++]; -+ if (rd->head == rd->entries) { -+ rd->head = 0; -+ } -+ return 1; -+} -+ -+/* -+ * ringtio_ring_put -+ */ -+static inline int ringtio_ring_put(struct uio_ubicom32ring_desc *rd, void *val) -+{ -+ unsigned int newtail = rd->tail + 1; -+ if (newtail == rd->entries) { -+ newtail = 0; -+ } -+ -+ if (newtail == rd->head) { -+ return 0; -+ } -+ -+ rd->ring[rd->tail] = (unsigned int)val; -+ rd->tail = newtail; -+ return 1; -+} -+ -+#endif /* _ASM_UBICOM32_UBICOM32RING_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32sd.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32sd.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32sd.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32sd.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,45 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32sd.h -+ * Ubicom32SD public include file -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#ifndef _ASM_UBICOM32_UBICOM32_SD_H -+#define _ASM_UBICOM32_UBICOM32_SD_H -+ -+struct ubicom32sd_card { -+ /* -+ * GPIOs of PWR, WP and CD lines. -+ * Polarity is 1 for active high and 0 for active low -+ */ -+ int pin_pwr; -+ bool pwr_polarity; -+ int pin_wp; -+ bool wp_polarity; -+ int pin_cd; -+ bool cd_polarity; -+}; -+ -+struct ubicom32sd_platform_data { -+ int ncards; -+ -+ struct ubicom32sd_card *cards; -+}; -+ -+#endif /* _ASM_UBICOM32_UBICOM32_SD_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32-spi-gpio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32-spi-gpio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32-spi-gpio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32-spi-gpio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,62 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32-spi-gpio.h -+ * Platform driver data definitions for GPIO based SPI driver. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_UBICOM32_SPI_GPIO_H -+#define _ASM_UBICOM32_UBICOM32_SPI_GPIO_H -+ -+struct ubicom32_spi_gpio_platform_data { -+ /* -+ * GPIO to use for MOSI, MISO, CLK -+ */ -+ int pin_mosi; -+ int pin_miso; -+ int pin_clk; -+ -+ /* -+ * Default state of CLK line -+ */ -+ int clk_default; -+ -+ /* -+ * Number of chip selects on this bus -+ */ -+ int num_chipselect; -+ -+ /* -+ * The bus number of this chip -+ */ -+ int bus_num; -+}; -+ -+struct ubicom32_spi_gpio_controller_data { -+ /* -+ * GPIO to use for chip select -+ */ -+ int pin_cs; -+}; -+ -+#endif /* _ASM_UBICOM32_UBICOM32_SPI_GPIO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32suart.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32suart.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32suart.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32suart.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,36 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32suart.h -+ * -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_UBICOM32_SUART_H -+#define _ASM_UBICOM32_UBICOM32_SUART_H -+ -+/* -+ * Platform resource id for serdes uart clock parameter -+ */ -+#define UBICOM32_SUART_IORESOURCE_CLOCK (1) -+ -+#endif /* _ASM_UBICOM32_UBICOM32_SUART_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32-tio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32-tio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ubicom32-tio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ubicom32-tio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,42 @@ -+/* -+ * arch/ubicom32/include/asm/ubicom32-tio.h -+ * Threaded I/O interface definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_UBICOM32_TIO_H -+#define _ASM_UBICOM32_UBICOM32_TIO_H -+ -+extern u8_t usb_tio_read_u16(u32_t address, u16_t *data); -+extern u8_t usb_tio_read_u8(u32_t address, u8_t *data); -+ -+extern u8_t usb_tio_write_u16(u32_t address, u16_t data); -+extern u8_t usb_tio_write_u8(u32_t address, u8_t data); -+ -+extern u8_t usb_tio_read_fifo(u32_t address, u32_t buffer, u32_t bytes); -+extern u8_t usb_tio_write_fifo(u32_t address, u32_t buffer, u32_t bytes); -+extern u8_t usb_tio_write_fifo_sync(u32_t address, u32_t buffer, u32_t bytes); -+extern void usb_tio_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx); -+ -+#endif /* _ASM_UBICOM32_UBICOM32_TIO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/ucontext.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ucontext.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/ucontext.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/ucontext.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,39 @@ -+/* -+ * arch/ubicom32/include/asm/ucontext.h -+ * Definition of ucontext structure for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_UCONTEXT_H -+#define _ASM_UBICOM32_UCONTEXT_H -+ -+struct ucontext { -+ unsigned long uc_flags; -+ struct ucontext *uc_link; -+ stack_t uc_stack; -+ struct sigcontext uc_mcontext; -+ sigset_t uc_sigmask; /* mask last for extensibility */ -+}; -+ -+#endif /* _ASM_UBICOM32_UCONTEXT_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/unaligned.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/unaligned.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/unaligned.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/unaligned.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,44 @@ -+/* -+ * arch/ubicom32/include/asm/unaligned.h -+ * Ubicom32 architecture unaligned memory access definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * -+ * TODO: This is a copy of arm unaligned handling that probably needs -+ * to be optimized for UBICOM32, but it works for now. -+ */ -+ -+#ifndef _ASM_UBICOM32_UNALIGNED_H -+#define _ASM_UBICOM32_UNALIGNED_H -+ -+#include -+ -+#include -+#include -+#include -+ -+#define get_unaligned __get_unaligned_be -+#define put_unaligned __put_unaligned_be -+ -+#endif /* _ASM_UBICOM32_UNALIGNED_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/unistd.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/unistd.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/unistd.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/unistd.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,400 @@ -+/* -+ * arch/ubicom32/include/asm/unistd.h -+ * Ubicom32 architecture syscall definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_UNISTD_H -+#define _ASM_UBICOM32_UNISTD_H -+ -+/* -+ * This file contains the system call numbers. -+ */ -+ -+#define __NR_restart_syscall 0 -+#define __NR_exit 1 -+#define __NR_fork 2 -+#define __NR_read 3 -+#define __NR_write 4 -+#define __NR_open 5 -+#define __NR_close 6 -+#define __NR_waitpid 7 -+#define __NR_creat 8 -+#define __NR_link 9 -+#define __NR_unlink 10 -+#define __NR_execve 11 -+#define __NR_chdir 12 -+#define __NR_time 13 -+#define __NR_mknod 14 -+#define __NR_chmod 15 -+#define __NR_chown 16 -+#define __NR_break 17 -+#define __NR_oldstat 18 -+#define __NR_lseek 19 -+#define __NR_getpid 20 -+#define __NR_mount 21 -+#define __NR_umount 22 -+#define __NR_setuid 23 -+#define __NR_getuid 24 -+#define __NR_stime 25 -+#define __NR_ptrace 26 -+#define __NR_alarm 27 -+#define __NR_oldfstat 28 -+#define __NR_pause 29 -+#define __NR_utime 30 -+#define __NR_stty 31 -+#define __NR_gtty 32 -+#define __NR_access 33 -+#define __NR_nice 34 -+#define __NR_ftime 35 -+#define __NR_sync 36 -+#define __NR_kill 37 -+#define __NR_rename 38 -+#define __NR_mkdir 39 -+#define __NR_rmdir 40 -+#define __NR_dup 41 -+#define __NR_pipe 42 -+#define __NR_times 43 -+#define __NR_prof 44 -+#define __NR_brk 45 -+#define __NR_setgid 46 -+#define __NR_getgid 47 -+#define __NR_signal 48 -+#define __NR_geteuid 49 -+#define __NR_getegid 50 -+#define __NR_acct 51 -+#define __NR_umount2 52 -+#define __NR_lock 53 -+#define __NR_ioctl 54 -+#define __NR_fcntl 55 -+#define __NR_mpx 56 -+#define __NR_setpgid 57 -+#define __NR_ulimit 58 -+#define __NR_oldolduname 59 -+#define __NR_umask 60 -+#define __NR_chroot 61 -+#define __NR_ustat 62 -+#define __NR_dup2 63 -+#define __NR_getppid 64 -+#define __NR_getpgrp 65 -+#define __NR_setsid 66 -+#define __NR_sigaction 67 -+#define __NR_sgetmask 68 -+#define __NR_ssetmask 69 -+#define __NR_setreuid 70 -+#define __NR_setregid 71 -+#define __NR_sigsuspend 72 -+#define __NR_sigpending 73 -+#define __NR_sethostname 74 -+#define __NR_setrlimit 75 -+#define __NR_getrlimit 76 -+#define __NR_getrusage 77 -+#define __NR_gettimeofday 78 -+#define __NR_settimeofday 79 -+#define __NR_getgroups 80 -+#define __NR_setgroups 81 -+#define __NR_select 82 -+#define __NR_symlink 83 -+#define __NR_oldlstat 84 -+#define __NR_readlink 85 -+#define __NR_uselib 86 -+#define __NR_swapon 87 -+#define __NR_reboot 88 -+#define __NR_readdir 89 -+#define __NR_mmap 90 -+#define __NR_munmap 91 -+#define __NR_truncate 92 -+#define __NR_ftruncate 93 -+#define __NR_fchmod 94 -+#define __NR_fchown 95 -+#define __NR_getpriority 96 -+#define __NR_setpriority 97 -+#define __NR_profil 98 -+#define __NR_statfs 99 -+#define __NR_fstatfs 100 -+#define __NR_ioperm 101 -+#define __NR_socketcall 102 -+#define __NR_syslog 103 -+#define __NR_setitimer 104 -+#define __NR_getitimer 105 -+#define __NR_stat 106 -+#define __NR_lstat 107 -+#define __NR_fstat 108 -+#define __NR_olduname 109 -+#define __NR_iopl /* 110 */ not supported -+#define __NR_vhangup 111 -+#define __NR_idle /* 112 */ Obsolete -+#define __NR_vm86 /* 113 */ not supported -+#define __NR_wait4 114 -+#define __NR_swapoff 115 -+#define __NR_sysinfo 116 -+#define __NR_ipc 117 -+#define __NR_fsync 118 -+#define __NR_sigreturn 119 -+#define __NR_clone 120 -+#define __NR_setdomainname 121 -+#define __NR_uname 122 -+#define __NR_cacheflush 123 -+#define __NR_adjtimex 124 -+#define __NR_mprotect 125 -+#define __NR_sigprocmask 126 -+#define __NR_create_module 127 -+#define __NR_init_module 128 -+#define __NR_delete_module 129 -+#define __NR_get_kernel_syms 130 -+#define __NR_quotactl 131 -+#define __NR_getpgid 132 -+#define __NR_fchdir 133 -+#define __NR_bdflush 134 -+#define __NR_sysfs 135 -+#define __NR_personality 136 -+#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ -+#define __NR_setfsuid 138 -+#define __NR_setfsgid 139 -+#define __NR__llseek 140 -+#define __NR_getdents 141 -+#define __NR__newselect 142 -+#define __NR_flock 143 -+#define __NR_msync 144 -+#define __NR_readv 145 -+#define __NR_writev 146 -+#define __NR_getsid 147 -+#define __NR_fdatasync 148 -+#define __NR__sysctl 149 -+#define __NR_mlock 150 -+#define __NR_munlock 151 -+#define __NR_mlockall 152 -+#define __NR_munlockall 153 -+#define __NR_sched_setparam 154 -+#define __NR_sched_getparam 155 -+#define __NR_sched_setscheduler 156 -+#define __NR_sched_getscheduler 157 -+#define __NR_sched_yield 158 -+#define __NR_sched_get_priority_max 159 -+#define __NR_sched_get_priority_min 160 -+#define __NR_sched_rr_get_interval 161 -+#define __NR_nanosleep 162 -+#define __NR_mremap 163 -+#define __NR_setresuid 164 -+#define __NR_getresuid 165 -+#define __NR_getpagesize 166 -+#define __NR_query_module 167 -+#define __NR_poll 168 -+#define __NR_nfsservctl 169 -+#define __NR_setresgid 170 -+#define __NR_getresgid 171 -+#define __NR_prctl 172 -+#define __NR_rt_sigreturn 173 -+#define __NR_rt_sigaction 174 -+#define __NR_rt_sigprocmask 175 -+#define __NR_rt_sigpending 176 -+#define __NR_rt_sigtimedwait 177 -+#define __NR_rt_sigqueueinfo 178 -+#define __NR_rt_sigsuspend 179 -+#define __NR_pread64 180 -+#define __NR_pwrite64 181 -+#define __NR_lchown 182 -+#define __NR_getcwd 183 -+#define __NR_capget 184 -+#define __NR_capset 185 -+#define __NR_sigaltstack 186 -+#define __NR_sendfile 187 -+#define __NR_getpmsg 188 /* some people actually want streams */ -+#define __NR_putpmsg 189 /* some people actually want streams */ -+#define __NR_vfork 190 -+#define __NR_ugetrlimit 191 -+#define __NR_mmap2 192 -+#define __NR_truncate64 193 -+#define __NR_ftruncate64 194 -+#define __NR_stat64 195 -+#define __NR_lstat64 196 -+#define __NR_fstat64 197 -+#define __NR_chown32 198 -+#define __NR_getuid32 199 -+#define __NR_getgid32 200 -+#define __NR_geteuid32 201 -+#define __NR_getegid32 202 -+#define __NR_setreuid32 203 -+#define __NR_setregid32 204 -+#define __NR_getgroups32 205 -+#define __NR_setgroups32 206 -+#define __NR_fchown32 207 -+#define __NR_setresuid32 208 -+#define __NR_getresuid32 209 -+#define __NR_setresgid32 210 -+#define __NR_getresgid32 211 -+#define __NR_lchown32 212 -+#define __NR_setuid32 213 -+#define __NR_setgid32 214 -+#define __NR_setfsuid32 215 -+#define __NR_setfsgid32 216 -+#define __NR_pivot_root 217 -+#define __NR_getdents64 220 -+#define __NR_gettid 221 -+#define __NR_tkill 222 -+#define __NR_setxattr 223 -+#define __NR_lsetxattr 224 -+#define __NR_fsetxattr 225 -+#define __NR_getxattr 226 -+#define __NR_lgetxattr 227 -+#define __NR_fgetxattr 228 -+#define __NR_listxattr 229 -+#define __NR_llistxattr 230 -+#define __NR_flistxattr 231 -+#define __NR_removexattr 232 -+#define __NR_lremovexattr 233 -+#define __NR_fremovexattr 234 -+#define __NR_futex 235 -+#define __NR_sendfile64 236 -+#define __NR_mincore 237 -+#define __NR_madvise 238 -+#define __NR_fcntl64 239 -+#define __NR_readahead 240 -+#define __NR_io_setup 241 -+#define __NR_io_destroy 242 -+#define __NR_io_getevents 243 -+#define __NR_io_submit 244 -+#define __NR_io_cancel 245 -+#define __NR_fadvise64 246 -+#define __NR_exit_group 247 -+#define __NR_lookup_dcookie 248 -+#define __NR_epoll_create 249 -+#define __NR_epoll_ctl 250 -+#define __NR_epoll_wait 251 -+#define __NR_remap_file_pages 252 -+#define __NR_set_tid_address 253 -+#define __NR_timer_create 254 -+#define __NR_timer_settime 255 -+#define __NR_timer_gettime 256 -+#define __NR_timer_getoverrun 257 -+#define __NR_timer_delete 258 -+#define __NR_clock_settime 259 -+#define __NR_clock_gettime 260 -+#define __NR_clock_getres 261 -+#define __NR_clock_nanosleep 262 -+#define __NR_statfs64 263 -+#define __NR_fstatfs64 264 -+#define __NR_tgkill 265 -+#define __NR_utimes 266 -+#define __NR_fadvise64_64 267 -+#define __NR_mbind 268 -+#define __NR_get_mempolicy 269 -+#define __NR_set_mempolicy 270 -+#define __NR_mq_open 271 -+#define __NR_mq_unlink 272 -+#define __NR_mq_timedsend 273 -+#define __NR_mq_timedreceive 274 -+#define __NR_mq_notify 275 -+#define __NR_mq_getsetattr 276 -+#define __NR_waitid 277 -+#define __NR_vserver 278 -+#define __NR_add_key 279 -+#define __NR_request_key 280 -+#define __NR_keyctl 281 -+#define __NR_ioprio_set 282 -+#define __NR_ioprio_get 283 -+#define __NR_inotify_init 284 -+#define __NR_inotify_add_watch 285 -+#define __NR_inotify_rm_watch 286 -+#define __NR_migrate_pages 287 -+#define __NR_openat 288 -+#define __NR_mkdirat 289 -+#define __NR_mknodat 290 -+#define __NR_fchownat 291 -+#define __NR_futimesat 292 -+#define __NR_fstatat64 293 -+#define __NR_unlinkat 294 -+#define __NR_renameat 295 -+#define __NR_linkat 296 -+#define __NR_symlinkat 297 -+#define __NR_readlinkat 298 -+#define __NR_fchmodat 299 -+#define __NR_faccessat 300 -+#define __NR_pselect6 301 -+#define __NR_ppoll 302 -+#define __NR_unshare 303 -+#define __NR_set_robust_list 304 -+#define __NR_get_robust_list 305 -+#define __NR_splice 306 -+#define __NR_sync_file_range 307 -+#define __NR_tee 308 -+#define __NR_vmsplice 309 -+#define __NR_move_pages 310 -+#define __NR_sched_setaffinity 311 -+#define __NR_sched_getaffinity 312 -+#define __NR_kexec_load 313 -+#define __NR_getcpu 314 -+#define __NR_epoll_pwait 315 -+#define __NR_utimensat 316 -+#define __NR_signalfd 317 -+#define __NR_timerfd_create 318 -+#define __NR_eventfd 319 -+#define __NR_fallocate 320 -+#define __NR_timerfd_settime 321 -+#define __NR_timerfd_gettime 322 -+#define __NR_signalfd4 323 -+#define __NR_eventfd2 324 -+#define __NR_epoll_create1 325 -+#define __NR_dup3 326 -+#define __NR_pipe2 327 -+#define __NR_inotify_init1 328 -+ -+#ifdef __KERNEL__ -+ -+#define NR_syscalls 329 -+ -+#define __ARCH_WANT_IPC_PARSE_VERSION -+#define __ARCH_WANT_OLD_READDIR -+#define __ARCH_WANT_OLD_STAT -+#define __ARCH_WANT_STAT64 -+#define __ARCH_WANT_SYS_ALARM -+#define __ARCH_WANT_SYS_GETHOSTNAME -+#define __ARCH_WANT_SYS_PAUSE -+#define __ARCH_WANT_SYS_SGETMASK -+#define __ARCH_WANT_SYS_SIGNAL -+#define __ARCH_WANT_SYS_TIME -+#define __ARCH_WANT_SYS_UTIME -+#define __ARCH_WANT_SYS_WAITPID -+#define __ARCH_WANT_SYS_SOCKETCALL -+#define __ARCH_WANT_SYS_FADVISE64 -+#define __ARCH_WANT_SYS_GETPGRP -+#define __ARCH_WANT_SYS_LLSEEK -+#define __ARCH_WANT_SYS_NICE -+#define __ARCH_WANT_SYS_OLD_GETRLIMIT -+#define __ARCH_WANT_SYS_OLDUMOUNT -+#define __ARCH_WANT_SYS_SIGPENDING -+#define __ARCH_WANT_SYS_SIGPROCMASK -+#define __ARCH_WANT_SYS_RT_SIGACTION -+ -+/* -+ * "Conditional" syscalls -+ * -+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))), -+ * but it doesn't work on all toolchains, so we just do it by hand -+ */ -+//#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") -+#define cond_syscall(x) long x(void) __attribute__((weak,alias("sys_ni_syscall"))) -+#endif /* __KERNEL__ */ -+ -+#endif /* _ASM_UBICOM32_UNISTD_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/user.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/user.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/user.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/user.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,82 @@ -+/* -+ * arch/ubicom32/include/asm/user.h -+ * Ubicom32 architecture core file definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_USER_H -+#define _ASM_UBICOM32_USER_H -+ -+#include -+#include -+/* -+ * Adapted from -+ * -+ * Core file format: The core file is written in such a way that gdb -+ * can understand it and provide useful information to the user (under -+ * linux we use the `trad-core' bfd, NOT the osf-core). The file contents -+ * are as follows: -+ * -+ * upage: 1 page consisting of a user struct that tells gdb -+ * what is present in the file. Directly after this is a -+ * copy of the task_struct, which is currently not used by gdb, -+ * but it may come in handy at some point. All of the registers -+ * are stored as part of the upage. The upage should always be -+ * only one page long. -+ * data: The data segment follows next. We use current->end_text to -+ * current->brk to pick up all of the user variables, plus any memory -+ * that may have been sbrk'ed. No attempt is made to determine if a -+ * page is demand-zero or if a page is totally unused, we just cover -+ * the entire range. All of the addresses are rounded in such a way -+ * that an integral number of pages is written. -+ * stack: We need the stack information in order to get a meaningful -+ * backtrace. We need to write the data from usp to -+ * current->start_stack, so we round each of these in order to be able -+ * to write an integer number of pages. -+ */ -+ -+struct user_ubicom32fp_struct { -+}; -+ -+struct user { -+ struct pt_regs regs; /* entire machine state */ -+ size_t u_tsize; /* text size (pages) */ -+ size_t u_dsize; /* data size (pages) */ -+ size_t u_ssize; /* stack size (pages) */ -+ unsigned long start_code; /* text starting address */ -+ unsigned long start_data; /* data starting address */ -+ unsigned long start_stack; /* stack starting address */ -+ long int signal; /* signal causing core dump */ -+ unsigned long u_ar0; /* help gdb find registers */ -+ unsigned long magic; /* identifies a core file */ -+ char u_comm[32]; /* user command name */ -+}; -+ -+#define NBPG PAGE_SIZE -+#define UPAGES 1 -+#define HOST_TEXT_START_ADDR (u.start_code) -+#define HOST_DATA_START_ADDR (u.start_data) -+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) -+ -+#endif /* _ASM_UBICOM32_USER_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/vdc_tio.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/vdc_tio.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/vdc_tio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/vdc_tio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,129 @@ -+/* -+ * arch/ubicom32/include/asm/vdc_tio.h -+ * Ubicom32 architecture VDC TIO definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_VDC_TIO_H -+#define _ASM_UBICOM32_VDC_TIO_H -+ -+#include -+ -+#define VDCTIO_VP_VERSION 5 -+ -+#define VDCTIO_SCALE_FLAG_VSUB (1 << 9) -+#define VDCTIO_SCALE_FLAG_YUV_SCAN_ORDER (1 << 8) -+#define VDCTIO_SCALE_FLAG_YUV_BLOCK_ORDER (1 << 7) -+#define VDCTIO_SCALE_FLAG_YUV (1 << 6) -+#define VDCTIO_SCALE_FLAG_VRANGE_16_255 (1 << 5) -+#define VDCTIO_SCALE_FLAG_VRANGE_0_255 (1 << 4) -+#define VDCTIO_SCALE_FLAG_HSUB_2_1 (1 << 3) -+#define VDCTIO_SCALE_FLAG_HSUB_1_1 (1 << 2) -+#define VDCTIO_SCALE_FLAG_SET_FRAME_BUFFER (1 << 1) -+#define VDCTIO_SCALE_FLAG_ENABLE (1 << 0) -+ -+#define VDCTIO_NEXT_FRAME_FLAG_YUV_BIT 0 -+#define VDCTIO_NEXT_FRAME_FLAG_YUV (1 << (VDCTIO_NEXT_FRAME_FLAG_YUV_BIT)) -+ -+#define VDCTIO_CAPS_SUPPORTS_SCALING (1 << 0) -+ -+#define VDCTIO_COMMAND_START (1 << 3) -+#define VDCTIO_COMMAND_SET_COEFF (1 << 2) -+#define VDCTIO_COMMAND_SET_LUT (1 << 1) -+#define VDCTIO_COMMAND_SET_SCALE_MODE (1 << 0) -+ -+/* -+ * Command / Data registers to access the VDC -+ */ -+struct vdc_tio_vp_regs { -+ /* -+ * Version of this TIO register map -+ */ -+ u32_t version; -+ -+ volatile u32_t command; -+ -+ /* -+ * Next frame pointer, when the command VDCTIO_COMMAND_SET_FRAME_BUFFER is set, -+ * the vdc will take the pointer here and display it. -+ */ -+ void *next_frame; -+ u32_t next_frame_flags; -+ -+ /* -+ * These map directly into the PIXP registers 0x20-0x80. -+ * DO NOT change the order of these three variables. -+ */ -+ u32_t red_lut[6]; -+ u32_t blue_lut[6]; -+ u32_t green_lut[13]; -+ -+ /* -+ * These map directly into the PIXP registers 0x04, 0x08 -+ */ -+ u32_t coeff0; -+ u32_t coeff1; -+ -+ /* -+ * There are used to set the scaling parameters -+ */ -+ u32_t x_in; -+ u32_t x_out; -+ u32_t y_in; -+ u32_t y_out; -+ u32_t scale_flags; -+ -+ /* -+ * Current frame number, monotonically increasing number -+ */ -+ u32_t frame_number; -+ -+ /* -+ * These variables tell the guest OS what the underlying hardware looks like -+ */ -+ u32_t caps; -+ u32_t xres; -+ u32_t yres; -+ u32_t fb_align; -+ u8_t bpp; -+ u8_t rbits; -+ u8_t gbits; -+ u8_t bbits; -+ u8_t rshift; -+ u8_t gshift; -+ u8_t bshift; -+}; -+ -+/* -+ * Devtree node for VDC -+ */ -+struct vdc_tio_node { -+ struct devtree_node dn; -+ -+ struct vdc_tio_vp_regs *regs; -+}; -+ -+extern void vdc_tio_init(void); -+ -+#endif /* _ASM_UBICOM32_VDC_TIO_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/vga.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/vga.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/vga.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/vga.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,71 @@ -+/* -+ * arch/ubicom32/include/asm/vga.h -+ * Ubicom32 low level VGA/frame buffer definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * (c) 1998 Martin Mares -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#ifndef _ASM_UBICOM32_VGA_H -+#define _ASM_UBICOM32_VGA_H -+ -+#include -+ -+/* -+ * On the PC, we can just recalculate addresses and then -+ * access the videoram directly without any black magic. -+ */ -+ -+#define VGA_MAP_MEM(x, s) (0xb0000000L + (unsigned long)(x)) -+ -+#define vga_readb(x) (*(x)) -+#define vga_writeb(x, y) (*(y) = (x)) -+ -+#define VT_BUF_HAVE_RW -+/* -+ * These are only needed for supporting VGA or MDA text mode, which use little -+ * endian byte ordering. -+ * In other cases, we can optimize by using native byte ordering and -+ * has already done the right job for us. -+ */ -+ -+#undef scr_writew -+#undef scr_readw -+ -+static inline void scr_writew(u16 val, volatile u16 *addr) -+{ -+ *addr = cpu_to_le16(val); -+} -+ -+static inline u16 scr_readw(volatile const u16 *addr) -+{ -+ return le16_to_cpu(*addr); -+} -+ -+#define scr_memcpyw(d, s, c) memcpy(d, s, c) -+#define scr_memmovew(d, s, c) memmove(d, s, c) -+#define VT_BUF_HAVE_MEMCPYW -+#define VT_BUF_HAVE_MEMMOVEW -+ -+#endif /* _ASM_UBICOM32_VGA_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/include/asm/xor.h linux-2.6.30.10-ubi/arch/ubicom32/include/asm/xor.h ---- linux-2.6.30.10/arch/ubicom32/include/asm/xor.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/include/asm/xor.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * arch/ubicom32/include/asm/xor.h -+ * Generic xor.h definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _ASM_UBICOM32_XOR_H -+#define _ASM_UBICOM32_XOR_H -+ -+#include -+ -+#endif /* _ASM_UBICOM32_XOR_H */ -diff -ruN linux-2.6.30.10/arch/ubicom32/Kconfig linux-2.6.30.10-ubi/arch/ubicom32/Kconfig ---- linux-2.6.30.10/arch/ubicom32/Kconfig 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/Kconfig 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,403 @@ -+# -+# For a description of the syntax of this configuration file, -+# see Documentation/kbuild/kconfig-language.txt. -+# -+ -+mainmenu "uClinux/ubicom32 (w/o MMU) Kernel Configuration" -+ -+config UBICOM32 -+ bool -+ select HAVE_OPROFILE -+ default y -+ -+config RAMKERNEL -+ bool -+ default y -+ -+config CPU_BIG_ENDIAN -+ bool -+ default y -+ -+config FORCE_MAX_ZONEORDER -+ int -+ default "14" -+ -+config HAVE_CLK -+ bool -+ default y -+ -+config MMU -+ bool -+ default n -+ -+config FPU -+ bool -+ default n -+ -+config ZONE_DMA -+ bool -+ default y -+ -+config RWSEM_GENERIC_SPINLOCK -+ bool -+ default y -+ -+config RWSEM_XCHGADD_ALGORITHM -+ bool -+ default n -+ -+config ARCH_HAS_ILOG2_U32 -+ bool -+ default n -+ -+config ARCH_HAS_ILOG2_U64 -+ bool -+ default n -+ -+config GENERIC_FIND_NEXT_BIT -+ bool -+ default y -+ -+config GENERIC_GPIO -+ bool -+ default y -+ -+config GPIOLIB -+ bool -+ default y -+ -+config GENERIC_HWEIGHT -+ bool -+ default y -+ -+config GENERIC_HARDIRQS -+ bool -+ default y -+ -+config STACKTRACE_SUPPORT -+ bool -+ default y -+ -+config LOCKDEP_SUPPORT -+ bool -+ default y -+ -+config GENERIC_CALIBRATE_DELAY -+ bool -+ default y -+ -+config GENERIC_TIME -+ bool -+ default y -+ -+config TIME_LOW_RES -+ bool -+ default y -+ -+config GENERIC_CLOCKEVENTS -+ bool -+ default y -+ -+config GENERIC_CLOCKEVENTS_BROADCAST -+ bool -+ depends on GENERIC_CLOCKEVENTS -+ default y if SMP && !LOCAL_TIMERS -+ -+config NO_IOPORT -+ def_bool y -+ -+config ARCH_SUPPORTS_AOUT -+ def_bool y -+ -+config IRQ_PER_CPU -+ bool -+ default y -+ -+config SCHED_NO_NO_OMIT_FRAME_POINTER -+ bool -+ default y -+ -+config UBICOM32_PLIO -+ bool -+ default n -+ -+menu "Processor type and features" -+ -+comment "Processor type will be selected by Board" -+ -+config UBICOM32_V3 -+ bool -+ help -+ Ubicom IP5xxx series processor support. -+ -+config UBICOM32_V4 -+ bool -+ help -+ Ubicom IP7xxx series processor support. -+ -+comment "Board" -+choice -+ prompt "Board type" -+ help -+ Select your board. -+ -+config NOBOARD -+ bool "No board selected" -+ help -+ Default. Don't select any board specific config. Will not build unless you change! -+ -+# Add your boards here -+source "arch/ubicom32/mach-ip5k/Kconfig" -+source "arch/ubicom32/mach-ip7k/Kconfig" -+ -+endchoice -+ -+comment "Kernel Options" -+config SMP -+ bool "Symmetric multi-processing support" -+ select USE_GENERIC_SMP_HELPERS -+ default n -+ help -+ Enables multithreading support. Enabling SMP support increases -+ the size of system data structures. SMP support can have either -+ positive or negative impact on performance depending on workloads. -+ -+ If you do not know what to do here, say N. -+config OLD_40400010_SYSTEM_CALL -+ bool "Provide old system call interface at 0x40400010" -+ default y -+ help -+ Provides the old system call interface, does not affect the -+ new system_call interface. -+ -+config NR_CPUS -+ int "Number of configured CPUs" -+ range 2 32 -+ default 2 -+ depends on SMP -+ help -+ Upper bound on the number of CPUs. Space is reserved -+ at compile time for this many CPUs. -+ -+config LOCAL_TIMERS -+ bool "Use local timer interrupts" -+ depends on SMP -+ default y -+ help -+ Enable support for local timers on SMP platforms, rather then the -+ legacy IPI broadcast method. Local timers allows the system -+ accounting to be spread across the timer interval, preventing a -+ "thundering herd" at every timer tick. A physical timer is allocated -+ per cpu. -+ -+config TIMER_EXTRA_ALLOC -+ int "Number of additional physical timer events to create" -+ depends on GENERIC_CLOCKEVENTS -+ default 0 -+ help -+ The Ubicom32 processor has a number of event timers that can be wrapped -+ in Linux clock event structures (assuming that the timers are not being -+ used for another purpose). Based on the value of LOCAL_TIMERS, either -+ 2 timers will be used or a timer will be used for every CPU. This value -+ allows the programmer to select additional timers over that amount. -+ -+config IRQSTACKS -+ bool "Create separate stacks for interrupt handling" -+ default n -+ help -+ Selecting this causes interrupts to be created on a separate -+ stack instead of nesting the interrupts on the kernel stack. -+ -+config IRQSTACKS_USEOCM -+ bool "Use OCM for interrupt stacks" -+ default n -+ depends on IRQSTACKS -+ help -+ Selecting this cause the interrupt stacks to be placed in OCM -+ reducing cache misses at the expense of using the OCM for servicing -+ interrupts. -+ -+menu "OCM Instruction Heap" -+ -+config OCM_MODULES_RESERVATION -+ int "OCM Instruction heap reservation. 0-192 kB" -+ range 0 192 -+ default "0" -+ help -+ The minimum amount of OCM memory to reserve for kernel loadable module -+ code. If you are not using this memory it cannot be used for anything -+ else. Leave it as 0 if you have prebuilt modules that are compiled with -+ OCM support. -+ -+config OCM_MODULES_MAY_CONSUME_REMAINING_CODESPACE -+ bool "Give all unused ocm code space to the ocm instruction heap." -+ default n -+ help -+ Allow the OCM instruction heap allocation to consume any remaining -+ unused OCM code space. The result of this is that you will not have -+ and deterministic results, but you will not have any waste either. -+ -+config OCM_MODULES_FALLBACK_TO_DDR -+ bool "Loadable Modules requiring OCM may fallback to use DDR." -+ default n -+ help -+ If a module cannot get the OCM code it requires allow DDR to -+ be used instead. -+endmenu -+ -+config HZ -+ int "Frequency of 'jiffies' (for polling)" -+ default 1000 -+ help -+ 100 is common for embedded systems, but 1000 allows -+ you to do more drivers without actually having -+ interrupts working properly. -+ -+comment "RAM configuration" -+ -+config MIN_RAMSIZE -+ hex "Minimum Size of RAM (in bytes)" -+ range 0x01000000 0x08000000 -+ default "0x02000000" -+ help -+ Define the minimum acceptable size of the system -+ RAM. Must be at least 16MB (0x01000000) -+ -+comment "Build options" -+config LINKER_RELAXATION -+ bool "Linker Relaxation" -+ default y -+ help -+ Turns on linker relaxation that will produce smaller -+ faster code. Increases link time. -+ -+comment "Driver options" -+menu "PCI Bus" -+config PCI -+ bool "PCI bus" -+ default true -+ help -+ Enable/Disable PCI bus -+ source "drivers/pci/Kconfig" -+ -+ -+config PCI_DEV0_IDSEL -+ hex "slot 0 address" -+ depends on PCI -+ default "0x01000000" -+ help -+ Slot 0 address. This address should correspond to the address line -+ which the IDSEL bit for this slot is connected to. -+ -+config PCI_DEV1_IDSEL -+ hex "slot 1 address" -+ depends on PCI -+ default "0x02000000" -+ help -+ Slot 1 address. This address should correspond to the address line -+ which the IDSEL bit for this slot is connected to. -+endmenu -+# End PCI -+ -+menu "Input devices" -+config UBICOM_INPUT -+ bool "Ubicom polled GPIO input driver" -+ select INPUT -+ select INPUT_POLLDEV -+ help -+ Polling input driver, much like the GPIO input driver, except that it doesn't -+ rely on interrupts. It will report events via the input subsystem. -+ default n -+ -+config UBICOM_INPUT_I2C -+ bool "Ubicom polled GPIO input driver over I2C" -+ select INPUT -+ select INPUT_POLLDEV -+ help -+ Polling input driver, much like the PCA953x driver, it can support a variety of -+ different I2C I/O expanders. This device polls the I2C I/O expander for events -+ and reports them via the input subsystem. -+ default n -+endmenu -+# Input devices -+ -+source "arch/ubicom32/mach-common/Kconfig.switch" -+ -+menu "Misc devices" -+config UBICOM_HID -+ bool "Ubicom HID driver" -+ select INPUT -+ select INPUT_POLLDEV -+ select LCD_CLASS_DEVICE -+ help -+ Driver for HID chip found on some Ubicom reference designs. This chip handles -+ PWM, button input, and IR remote control. It registers as an input device and -+ a backlight device. -+ default n -+endmenu -+# Misc devices -+ -+config CMDLINE_BOOL -+ bool "Built-in kernel command line" -+ default n -+ help -+ Allow for specifying boot arguments to the kernel at -+ build time. On some systems (e.g. embedded ones), it is -+ necessary or convenient to provide some or all of the -+ kernel boot arguments with the kernel itself (that is, -+ to not rely on the boot loader to provide them.) -+ -+ To compile command line arguments into the kernel, -+ set this option to 'Y', then fill in the -+ the boot arguments in CONFIG_CMDLINE. -+ -+ Systems with fully functional boot loaders (i.e. non-embedded) -+ should leave this option set to 'N'. -+ -+config CMDLINE -+ string "Built-in kernel command string" -+ depends on CMDLINE_BOOL -+ default "" -+ help -+ Enter arguments here that should be compiled into the kernel -+ image and used at boot time. If the boot loader provides a -+ command line at boot time, it is appended to this string to -+ form the full kernel command line, when the system boots. -+ -+ However, you can use the CONFIG_CMDLINE_OVERRIDE option to -+ change this behavior. -+ -+ In most cases, the command line (whether built-in or provided -+ by the boot loader) should specify the device for the root -+ file system. -+ -+config CMDLINE_OVERRIDE -+ bool "Built-in command line overrides boot loader arguments" -+ default n -+ depends on CMDLINE_BOOL -+ help -+ Set this option to 'Y' to have the kernel ignore the boot loader -+ command line, and use ONLY the built-in command line. -+ -+ This is used to work around broken boot loaders. This should -+ be set to 'N' under normal conditions. -+ -+endmenu -+# End Processor type and features -+ -+source "arch/ubicom32/Kconfig.debug" -+ -+menu "Executable file formats" -+source "fs/Kconfig.binfmt" -+endmenu -+ -+source "init/Kconfig" -+source "kernel/Kconfig.preempt" -+source "kernel/time/Kconfig" -+source "mm/Kconfig" -+source "net/Kconfig" -+source "drivers/Kconfig" -+source "fs/Kconfig" -+source "security/Kconfig" -+source "crypto/Kconfig" -+source "lib/Kconfig" -diff -ruN linux-2.6.30.10/arch/ubicom32/Kconfig.debug linux-2.6.30.10-ubi/arch/ubicom32/Kconfig.debug ---- linux-2.6.30.10/arch/ubicom32/Kconfig.debug 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/Kconfig.debug 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,129 @@ -+menu "Kernel hacking" -+ -+config TRACE_IRQFLAGS_SUPPORT -+ def_bool y -+ -+config DEBUG_VERBOSE -+ bool "Verbose fault messages" -+ default y -+ select PRINTK -+ help -+ When a program crashes due to an exception, or the kernel detects -+ an internal error, the kernel can print a not so brief message -+ explaining what the problem was. This debugging information is -+ useful to developers and kernel hackers when tracking down problems, -+ but mostly meaningless to other people. This is always helpful for -+ debugging but serves no purpose on a production system. -+ Most people should say N here. -+ -+config PROTECT_KERNEL -+ default y -+ bool 'Enable Kernel range register Protection' -+ help -+ Adds code to enable/disable range registers to protect static -+ kernel code/data from userspace. Currently the ranges covered -+ do no protect kernel loadable modules or dynamically allocated -+ kernel data. -+ -+config NO_KERNEL_MSG -+ bool "Suppress Kernel BUG Messages" -+ help -+ Do not output any debug BUG messages within the kernel. -+ -+config EARLY_PRINTK -+ bool "Use the driver that you selected as console also for early printk (to debug kernel bootup)." -+ default n -+ help -+ If you want to use the serdes driver (console=ttyUS0) for -+ early printk, you must also supply an additional kernel boot -+ parameter like this: -+ -+ serdes=ioportaddr,irq,clockrate,baud -+ -+ For an IP7160RGW eval board, you could use this: -+ -+ serdes=0x2004000,61,250000000,57600 -+ -+ which will let you see early printk output at 57600 baud. -+ -+config STOP_ON_TRAP -+ bool "Enable stopping at the LDSR for all traps" -+ default n -+ help -+ Cause the LDSR to stop all threads whenever a trap is about to be serviced -+ -+config STOP_ON_BUG -+ bool "Enable stopping on failed BUG_ON()" -+ default n -+ help -+ Cause all BUG_ON failures to stop all threads -+ -+config DEBUG_IRQMEASURE -+ bool "Enable IRQ handler measurements" -+ default n -+ help -+ When enabled each IRQ's min/avg/max times will be printed. If the handler -+ re-enables interrupt, the times will show the full time including to service -+ nested interrupts. See /proc/irq_measurements. -+ -+config DEBUG_PCIMEASURE -+ bool "Enable PCI transaction measurements" -+ default n -+ help -+ When enabled the system will measure the min/avg/max timer for each PCI transactions. -+ See /proc/pci_measurements. -+ -+config ACCESS_OK_CHECKS_ENABLED -+ bool "Enable user space access checks" -+ default n -+ help -+ Enabling this check causes the kernel to verify that addresses passed -+ to the kernel by the user space code are within the processes -+ address space. On a no-mmu system, this is done by examining the -+ processes memory data structures (adversly affecting performance) but -+ ensuring that a process does not ask the kernel to violate another -+ processes address space. Sadly, the kernel uses access_ok() for -+ address that are in the kernel which results in a large volume of -+ false positives. -+ -+choice -+ prompt "Unaligned Access Support" -+ default UNALIGNED_ACCESS_ENABLED -+ help -+ Kernel / Userspace unaligned access handling. -+ -+config UNALIGNED_ACCESS_ENABLED -+ bool "Kernel and Userspace" -+ help -+ -+config UNALIGNED_ACCESS_USERSPACE_ONLY -+ bool "Userspace Only" -+ help -+ -+config UNALIGNED_ACCESS_DISABLED -+ bool "Disabled" -+ help -+ -+endchoice -+ -+config DEBUG_STACKOVERFLOW -+ bool "Check for stack overflows" -+ default n -+ depends on DEBUG_KERNEL -+ help -+ This option will cause messages to be printed if free kernel stack space -+ drops below a certain limit (THREAD_SIZE /8). -+ -+config DEBUG_STACK_USAGE -+ bool "Stack utilization instrumentation" -+ default n -+ depends on DEBUG_KERNEL -+ help -+ Enables the display of the minimum amount of free kernel stack which each -+ task has ever had available in the sysrq-T and sysrq-P debug output. -+ -+ This option will slow down process creation somewhat. -+ -+source "lib/Kconfig.debug" -+ -+endmenu -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/asm-offsets.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/asm-offsets.c ---- linux-2.6.30.10/arch/ubicom32/kernel/asm-offsets.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/asm-offsets.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,161 @@ -+/* -+ * arch/ubicom32/kernel/asm-offsets.c -+ * Ubicom32 architecture definitions needed by assembly language modules. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+/* -+ * This program is used to generate definitions needed by -+ * assembly language modules. -+ * -+ * We use the technique used in the OSF Mach kernel code: -+ * generate asm statements containing #defines, -+ * compile this file to assembler, and then extract the -+ * #defines from the assembly-language output. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEFINE(sym, val) \ -+ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) -+ -+#define BLANK() asm volatile("\n->" : : ) -+ -+int main(void) -+{ -+ /* offsets into the task struct */ -+ DEFINE(TASK_STATE, offsetof(struct task_struct, state)); -+ DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); -+ DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); -+ DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); -+ DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); -+ DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack)); -+ DEFINE(TASK_MM, offsetof(struct task_struct, mm)); -+ DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); -+ -+ /* offsets into the kernel_stat struct */ -+// DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); -+ -+ /* offsets into the irq_cpustat_t struct */ -+ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); -+ -+ /* offsets into the thread struct */ -+ DEFINE(THREAD_D10, offsetof(struct thread_struct, d10)); -+ DEFINE(THREAD_D11, offsetof(struct thread_struct, d11)); -+ DEFINE(THREAD_D12, offsetof(struct thread_struct, d12)); -+ DEFINE(THREAD_D13, offsetof(struct thread_struct, d13)); -+ DEFINE(THREAD_A1, offsetof(struct thread_struct, a1)); -+ DEFINE(THREAD_A2, offsetof(struct thread_struct, a2)); -+ DEFINE(THREAD_A5, offsetof(struct thread_struct, a5)); -+ DEFINE(THREAD_A6, offsetof(struct thread_struct, a6)); -+ DEFINE(THREAD_SP, offsetof(struct thread_struct, sp)); -+ -+ /* offsets into the pt_regs */ -+ DEFINE(PT_D0, offsetof(struct pt_regs, dn[0])); -+ DEFINE(PT_D1, offsetof(struct pt_regs, dn[1])); -+ DEFINE(PT_D2, offsetof(struct pt_regs, dn[2])); -+ DEFINE(PT_D3, offsetof(struct pt_regs, dn[3])); -+ DEFINE(PT_D4, offsetof(struct pt_regs, dn[4])); -+ DEFINE(PT_D5, offsetof(struct pt_regs, dn[5])); -+ DEFINE(PT_D6, offsetof(struct pt_regs, dn[6])); -+ DEFINE(PT_D7, offsetof(struct pt_regs, dn[7])); -+ DEFINE(PT_D8, offsetof(struct pt_regs, dn[8])); -+ DEFINE(PT_D9, offsetof(struct pt_regs, dn[9])); -+ DEFINE(PT_D10, offsetof(struct pt_regs, dn[10])); -+ DEFINE(PT_D11, offsetof(struct pt_regs, dn[11])); -+ DEFINE(PT_D12, offsetof(struct pt_regs, dn[12])); -+ DEFINE(PT_D13, offsetof(struct pt_regs, dn[13])); -+ DEFINE(PT_D14, offsetof(struct pt_regs, dn[14])); -+ DEFINE(PT_D15, offsetof(struct pt_regs, dn[15])); -+ DEFINE(PT_A0, offsetof(struct pt_regs, an[0])); -+ DEFINE(PT_A1, offsetof(struct pt_regs, an[1])); -+ DEFINE(PT_A2, offsetof(struct pt_regs, an[2])); -+ DEFINE(PT_A3, offsetof(struct pt_regs, an[3])); -+ DEFINE(PT_A4, offsetof(struct pt_regs, an[4])); -+ DEFINE(PT_A5, offsetof(struct pt_regs, an[5])); -+ DEFINE(PT_A6, offsetof(struct pt_regs, an[6])); -+ DEFINE(PT_A7, offsetof(struct pt_regs, an[7])); -+ DEFINE(PT_SP, offsetof(struct pt_regs, an[7])); -+ -+ DEFINE(PT_ACC0HI, offsetof(struct pt_regs, acc0[0])); -+ DEFINE(PT_ACC0LO, offsetof(struct pt_regs, acc0[1])); -+ DEFINE(PT_MAC_RC16, offsetof(struct pt_regs, mac_rc16)); -+ -+ DEFINE(PT_ACC1HI, offsetof(struct pt_regs, acc1[0])); -+ DEFINE(PT_ACC1LO, offsetof(struct pt_regs, acc1[1])); -+ -+ DEFINE(PT_SOURCE3, offsetof(struct pt_regs, source3)); -+ DEFINE(PT_INST_CNT, offsetof(struct pt_regs, inst_cnt)); -+ DEFINE(PT_CSR, offsetof(struct pt_regs, csr)); -+ DEFINE(PT_DUMMY_UNUSED, offsetof(struct pt_regs, dummy_unused)); -+ -+ DEFINE(PT_INT_MASK0, offsetof(struct pt_regs, int_mask0)); -+ DEFINE(PT_INT_MASK1, offsetof(struct pt_regs, int_mask1)); -+ -+ DEFINE(PT_PC, offsetof(struct pt_regs, pc)); -+ -+ DEFINE(PT_TRAP_CAUSE, offsetof(struct pt_regs, trap_cause)); -+ -+ DEFINE(PT_SIZE, sizeof(struct pt_regs)); -+ -+ DEFINE(PT_FRAME_TYPE, offsetof(struct pt_regs, frame_type)); -+ -+ DEFINE(PT_ORIGINAL_D0, offsetof(struct pt_regs, original_dn_0)); -+ DEFINE(PT_PREVIOUS_PC, offsetof(struct pt_regs, previous_pc)); -+ -+ /* offsets into the kernel_stat struct */ -+// DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); -+ -+ /* signal defines */ -+ DEFINE(SIGSEGV, SIGSEGV); -+ //DEFINE(SEGV_MAPERR, SEGV_MAPERR); -+ DEFINE(SIGTRAP, SIGTRAP); -+ //DEFINE(TRAP_TRACE, TRAP_TRACE); -+ -+ DEFINE(PT_PTRACED, PT_PTRACED); -+ DEFINE(PT_DTRACE, PT_DTRACE); -+ -+ DEFINE(ASM_THREAD_SIZE, THREAD_SIZE); -+ -+ /* Offsets in thread_info structure */ -+ DEFINE(TI_TASK, offsetof(struct thread_info, task)); -+ DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); -+ DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); -+ DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count)); -+ DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); -+ DEFINE(TI_INTR_NESTING, offsetof(struct thread_info, interrupt_nesting)); -+ DEFINE(ASM_TIF_NEED_RESCHED, TIF_NEED_RESCHED); -+ DEFINE(ASM_TIF_SYSCALL_TRACE, TIF_SYSCALL_TRACE); -+ DEFINE(ASM_TIF_SIGPENDING, TIF_SIGPENDING); -+ -+ return 0; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/devtree.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/devtree.c ---- linux-2.6.30.10/arch/ubicom32/kernel/devtree.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/devtree.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,173 @@ -+/* -+ * arch/ubicom32/kernel/devtree.c -+ * Ubicom32 architecture device tree implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * The device tree. -+ */ -+struct devtree_node *devtree; -+ -+/* -+ * devtree_print() -+ * Print the device tree. -+ */ -+void devtree_print(void) -+{ -+ struct devtree_node *p = devtree; -+ printk(KERN_INFO "Device Tree:\n"); -+ while (p) { -+ if (p->magic != DEVTREE_NODE_MAGIC) { -+ printk(KERN_EMERG -+ "device tree has improper node: %p\n", p); -+ return; -+ } -+ printk(KERN_INFO "\t%p: sendirq=%03d, recvirq=%03d, " -+ " name=%s\n", p, p->sendirq, p->recvirq, p->name); -+ p = p->next; -+ } -+} -+EXPORT_SYMBOL(devtree_print); -+ -+/* -+ * devtree_irq() -+ * Return the IRQ(s) associated with devtree node. -+ */ -+int devtree_irq(struct devtree_node *dn, -+ unsigned char *sendirq, -+ unsigned char *recvirq) -+{ -+ if (dn->magic != DEVTREE_NODE_MAGIC) { -+ printk(KERN_EMERG "improper node: %p\n", dn); -+ if (sendirq) { -+ *sendirq = DEVTREE_IRQ_NONE; -+ } -+ if (recvirq) { -+ *recvirq = DEVTREE_IRQ_NONE; -+ } -+ return -EFAULT; -+ } -+ -+ /* -+ * Copy the devtree irq(s) to the output parameters. -+ */ -+ if (sendirq) { -+ *sendirq = dn->sendirq; -+ } -+ if (recvirq) { -+ *recvirq = dn->recvirq; -+ } -+ return 0; -+} -+EXPORT_SYMBOL(devtree_irq); -+ -+/* -+ * devtree_find_next() -+ * Provide an iterator for walking the device tree. -+ */ -+struct devtree_node *devtree_find_next(struct devtree_node **cur) -+{ -+ struct devtree_node *p = *cur; -+ if (!p) { -+ *cur = devtree; -+ return devtree; -+ } -+ p = p->next; -+ *cur = p; -+ return p; -+} -+ -+/* -+ * devtree_find_by_irq() -+ * Return the node associated with a given irq. -+ */ -+struct devtree_node *devtree_find_by_irq(uint8_t sendirq, uint8_t recvirq) -+{ -+ struct devtree_node *p = devtree; -+ -+ if (sendirq == recvirq) { -+ printk(KERN_EMERG "identical request makes no sense sendirq = " -+ "%d, recvirq= %d\n", sendirq, recvirq); -+ return NULL; -+ } -+ -+ while (p) { -+ if (p->magic != DEVTREE_NODE_MAGIC) { -+ printk(KERN_EMERG -+ "device tree has improper node: %p\n", p); -+ return NULL; -+ } -+ -+ /* -+ * See if we can find a match on the IRQ(s) specified. -+ */ -+ if ((sendirq == p->sendirq) && (recvirq == p->recvirq)) { -+ return p; -+ } -+ -+ if ((sendirq == DEVTREE_IRQ_DONTCARE) && -+ (p->recvirq == recvirq)) { -+ return p; -+ } -+ -+ if ((recvirq == DEVTREE_IRQ_DONTCARE) && -+ (p->sendirq == sendirq)) { -+ return p; -+ } -+ -+ p = p->next; -+ } -+ return NULL; -+} -+EXPORT_SYMBOL(devtree_find_by_irq); -+ -+/* -+ * devtree_find_node() -+ * Find a node in the device tree by name. -+ */ -+struct devtree_node *devtree_find_node(const char *str) -+{ -+ struct devtree_node *p = devtree; -+ while (p) { -+ if (p->magic != DEVTREE_NODE_MAGIC) { -+ printk(KERN_EMERG -+ "device tree has improper node: %p\n", p); -+ return NULL; -+ } -+ if (strcmp(p->name, str) == 0) { -+ return p; -+ } -+ p = p->next; -+ } -+ return NULL; -+} -+EXPORT_SYMBOL(devtree_find_node); -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/dma.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/dma.c ---- linux-2.6.30.10/arch/ubicom32/kernel/dma.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/dma.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,60 @@ -+/* -+ * arch/ubicom32/kernel/dma.c -+ * Ubicom32 architecture dynamic DMA mapping support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * -+ * We never have any address translations to worry about, so this -+ * is just alloc/free. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+void *dma_alloc_coherent(struct device *dev, size_t size, -+ dma_addr_t *dma_handle, int gfp) -+{ -+ void *ret; -+ /* ignore region specifiers */ -+ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); -+ -+ if (dev == NULL || (*dev->dma_mask < 0xffffffff)) -+ gfp |= GFP_DMA; -+ ret = (void *)__get_free_pages(gfp, get_order(size)); -+ -+ if (ret != NULL) { -+ memset(ret, 0, size); -+ *dma_handle = virt_to_phys(ret); -+ } -+ return ret; -+} -+ -+void dma_free_coherent(struct device *dev, size_t size, -+ void *vaddr, dma_addr_t dma_handle) -+{ -+ free_pages((unsigned long)vaddr, get_order(size)); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/flat.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/flat.c ---- linux-2.6.30.10/arch/ubicom32/kernel/flat.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/flat.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,206 @@ -+/* -+ * arch/ubicom32/kernel/flat.c -+ * Ubicom32 architecture flat executable format support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+ -+unsigned long ubicom32_flat_get_addr_from_rp(unsigned long *rp, -+ u32_t relval, -+ u32_t flags, -+ unsigned long *persistent) -+{ -+ u32_t relval_reloc_type = relval >> 27; -+ u32_t insn = *rp; -+ -+ if (*persistent) { -+ /* -+ * relval holds the relocation that has to be adjusted. -+ */ -+ if (relval == 0) { -+ *persistent = 0; -+ } -+ -+ return relval; -+ } -+ -+ if (relval_reloc_type == R_UBICOM32_32) { -+ /* -+ * insn holds the relocation -+ */ -+ return insn; -+ } -+ -+ /* -+ * We don't know this one. -+ */ -+ return 0; -+} -+ -+void ubicom32_flat_put_addr_at_rp(unsigned long *rp, -+ u32_t val, -+ u32_t relval, -+ unsigned long *persistent) -+{ -+ u32_t reloc_type = (relval >> 27) & 0x1f; -+ u32_t insn = *rp; -+ -+ /* -+ * If persistent is set then it contains the relocation type. -+ */ -+ if (*persistent) { -+ /* -+ * If persistent is set then it contains the relocation type. -+ */ -+ reloc_type = (*persistent >> 27) & 0x1f; -+ } -+ -+ switch (reloc_type) { -+ case R_UBICOM32_32: -+ /* -+ * Store the 32 bits as is. -+ */ -+ *rp = val; -+ break; -+ case R_UBICOM32_HI24: -+ { -+ /* -+ * 24 bit relocation that is part of the MOVEAI -+ * instruction. The 24 bits come from bits 7 - 30 of the -+ * relocation. The 24 bits eventually get split into 2 -+ * fields in the instruction encoding. -+ * -+ * - Bits 7 - 27 of the relocation are encoded into bits -+ * 0 - 20 of the instruction. -+ * -+ * - Bits 28 - 30 of the relocation are encoded into bit -+ * 24 - 26 of the instruction. -+ */ -+ u32_t mask = 0x1fffff | (0x7 << 24); -+ u32_t valid24bits = (val >> 7) & 0xffffff; -+ u32_t bot_21 = valid24bits & 0x1fffff; -+ u32_t upper_3_bits = ((valid24bits & 0xe00000) << 3); -+ insn &= ~mask; -+ -+ insn |= bot_21; -+ insn |= upper_3_bits; -+ *rp = insn; -+ } -+ break; -+ case R_UBICOM32_LO7_S: -+ case R_UBICOM32_LO7_2_S: -+ case R_UBICOM32_LO7_4_S: -+ { -+ /* -+ * Bits 0 - 6 of the relocation are encoded into the -+ * 7bit unsigned immediate fields of the SOURCE-1 field -+ * of the instruction. The immediate value is left -+ * shifted by (0, 1, 2) based on the operand size. -+ */ -+ u32_t mask = 0x1f | (0x3 << 8); -+ u32_t bottom, top; -+ val &= 0x7f; -+ if (reloc_type == R_UBICOM32_LO7_2_S) { -+ val >>= 1; -+ } else if (reloc_type == R_UBICOM32_LO7_4_S) { -+ val >>= 2; -+ } -+ -+ bottom = val & 0x1f; -+ top = val >> 5; -+ insn &= ~mask; -+ insn |= bottom; -+ insn |= (top << 8); -+ BUG_ON(*rp != insn); -+ *rp = insn; -+ break; -+ } -+ case R_UBICOM32_LO7_D: -+ case R_UBICOM32_LO7_2_D: -+ case R_UBICOM32_LO7_4_D: -+ { -+ /* -+ * Bits 0 - 6 of the relocation are encoded into the -+ * 7bit unsigned immediate fields of the DESTINATION -+ * field of the instruction. The immediate value is -+ * left shifted by (0, 1, 2) based on the operand size. -+ */ -+ u32_t mask = (0x1f | (0x3 << 8)) << 16; -+ u32_t bottom, top; -+ val &= 0x7f; -+ if (reloc_type == R_UBICOM32_LO7_2_D) { -+ val >>= 1; -+ } else if (reloc_type == R_UBICOM32_LO7_4_D) { -+ val >>= 2; -+ } -+ bottom = (val & 0x1f) << 16; -+ top = (val >> 5) << 16; -+ insn &= ~mask; -+ insn |= bottom; -+ insn |= (top << 8); -+ BUG_ON(*rp != insn); -+ *rp = insn; -+ break; -+ } -+ case R_UBICOM32_LO7_CALLI: -+ case R_UBICOM32_LO16_CALLI: -+ { -+ /* -+ * Extract the offset for a CALLI instruction. The -+ * offsets can be either 7 bits or 18 bits. Since all -+ * instructions in ubicom32 architecture are at work -+ * aligned addresses the truncated offset is right -+ * shifted by 2 before being encoded in the instruction. -+ */ -+ if (reloc_type == R_UBICOM32_LO7_CALLI) { -+ val &= 0x7f; -+ } else { -+ val &= 0x3ffff; -+ } -+ -+ val >>= 2; -+ -+ insn &= ~0x071f071f; -+ insn |= (val & 0x1f) << 0; -+ val >>= 5; -+ insn |= (val & 0x07) << 8; -+ val >>= 3; -+ insn |= (val & 0x1f) << 16; -+ val >>= 5; -+ insn |= (val & 0x07) << 24; -+ if (reloc_type == R_UBICOM32_LO7_CALLI) { -+ BUG_ON(*rp != insn); -+ } -+ *rp = insn; -+ } -+ break; -+ } -+ -+ if (*persistent) { -+ *persistent = 0; -+ } -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/head.S linux-2.6.30.10-ubi/arch/ubicom32/kernel/head.S ---- linux-2.6.30.10/arch/ubicom32/kernel/head.S 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/head.S 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,273 @@ -+/* -+ * arch/ubicom32/kernel/head.S -+ * -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#define __ASM__ -+#include -+ -+ -+#define SRC_AN A3 -+#define DST_AN A4 -+ -+#define PARAM_DN D0 -+#define TMP_DN D15 -+#define TMP2_DN D14 -+ -+/* -+ * The following code is placed at the start of the Linux section of memory. -+ * This is the primary entry point for Linux. -+ * -+ * However, we also want the syscall entry/exit code to be at a fixed address. -+ * So we take the primary entry point and reserve 16 bytes. That address is -+ * where the system_call entry point exists. This 16 bytes basically allows -+ * us to jump around the system_call entry point code to the actual startup -+ * code. -+ * -+ * Linux Memory Map (see vlinux.lds.S): -+ * 0x40400000 - Primary Entry Point for Linux (jump around code below). -+ * 0x40400010 - Old syscall Entry Point. -+ */ -+ -+ .sect .skip_syscall, "ax", @progbits -+ .global __skip_syscall_section -+__skip_syscall_section: -+ moveai A3, #%hi(_start) -+ lea.1 A3, %lo(_start)(A3) -+ ret A3 -+/* -+ * __os_node_offset contains the offset from KERNELBASE to the os_node, it is -+ * not intended to be used by anything except the boot code. -+ */ -+__os_node_offset: -+.long (_os_node - KERNELSTART) -+ -+.text -+.global _start -+ -+/* -+ * start() -+ * This is the start of the Linux kernel. -+ */ -+_start: -+ move.4 SCRATCHPAD1, #0 -+ -+ -+/* -+ * Setup the range registers... the loader has setup a few, but we will go ahead -+ * and correct them for our own limits. Note that once set these are never -+ * changed again. The ranges are as follows -+ * -+ * D_RANGE0 - io block (set up by loaded) -+ * -+ * I_RANGE0 and D_RANGE1 - kernel/ultra loader address space bottom of ocm-> top -+ * of ram typically 0x3ffc0000 - 0x440000000 -+ * I_RANGE1 - kernel / userspace transition area (aka syscalls, context switches) -+ * typically 0x3FFC0030 - ~0x3FFC0200 -+ * I_RANGE2 / D_RANGE2 - slab area -+ * typically 0x40A00000 - ~0x44000000 -+ * I_RANGE3 -+ * old system call interface if enabled. -+ * -+ * D_RANGE3, D_RANGE4 - unused. -+ */ -+ moveai SRC_AN, #%hi(PAGE_OFFSET_RAW) -+ lea.4 SRC_AN, %lo(PAGE_OFFSET_RAW)(SRC_AN) -+ move.4 D_RANGE1_LO, SRC_AN -+ move.4 I_RANGE0_LO, SRC_AN -+ -+; don't try to calculate I_RANGE_HI, see below -+; moveai SRC_AN, #%hi(___init_end-4) -+; lea.4 SRC_AN, %lo(___init_end-4)(SRC_AN) -+; move.4 I_RANGE0_HI, SRC_AN -+ -+ moveai SRC_AN, #%hi(SDRAMSTART + CONFIG_MIN_RAMSIZE-4) -+ lea.4 SRC_AN, %lo(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)(SRC_AN) -+ move.4 D_RANGE1_HI, SRC_AN -+ -+; for now allow the whole ram to be executable as well so we don't run into problems -+; once we load user more code. -+ move.4 I_RANGE0_HI, SRC_AN -+ -+#ifdef CONFIG_PROTECT_KERNEL -+; when kernel protection is enabled, we only open up syscall and non kernel text -+; for userspace apps, for now only irange registers registers 1 and 2 are used for userspace. -+ -+ ;; syscall range -+ moveai SRC_AN, #%hi(__syscall_text_run_begin) -+ lea.4 SRC_AN, %lo(__syscall_text_run_begin)(SRC_AN) -+ move.4 I_RANGE1_LO, SRC_AN -+ moveai SRC_AN, #%hi(__syscall_text_run_end) -+ lea.4 SRC_AN, %lo(__syscall_text_run_end)(SRC_AN) -+ move.4 I_RANGE1_HI, SRC_AN -+ -+ ;; slab instructions -+ moveai SRC_AN, #%hi(_edata) -+ lea.4 SRC_AN, %lo(_edata)(SRC_AN) -+ move.4 I_RANGE2_LO, SRC_AN -+ ;; End of DDR is already in range0 hi so just copy it. -+ move.4 I_RANGE2_HI, I_RANGE0_HI -+ -+#ifdef CONFIG_OLD_40400010_SYSTEM_CALL -+ ;; create a small hole for old syscall location -+ moveai SRC_AN, #%hi(0x40400000) -+ lea.4 I_RANGE3_LO, 0x10(SRC_AN) -+ lea.4 I_RANGE3_HI, 0x14(SRC_AN) -+#endif -+ ;; slab data (same as slab instructions but starting a little earlier). -+ moveai SRC_AN, #%hi(_data_protection_end) -+ lea.4 SRC_AN, %lo(_data_protection_end)(SRC_AN) -+ move.4 D_RANGE2_LO, SRC_AN -+ move.4 D_RANGE2_HI, I_RANGE0_HI -+ -+;; enable ranges -+ ;; skip I_RANGE0_EN -+ move.4 I_RANGE1_EN, #-1 -+ move.4 I_RANGE2_EN, #-1 -+#ifdef CONFIG_OLD_40400010_SYSTEM_CALL -+ move.4 I_RANGE3_EN, #-1 -+#else -+ move.4 I_RANGE3_EN, #0 -+#endif -+ ;; skip D_RANGE0_EN or D_RANGE1_EN -+ move.4 D_RANGE2_EN, #-1 -+ move.4 D_RANGE3_EN, #0 -+ move.4 D_RANGE4_EN, #0 -+#endif -+ -+; -+; If __ocm_free_begin is smaller than __ocm_free_end the -+; setup OCM text and data ram banks properly -+; -+ moveai DST_AN, #%hi(__ocm_free_begin) -+ lea.4 TMP_DN, %lo(__ocm_free_begin)(DST_AN) -+ moveai DST_AN, #%hi(__ocm_free_end) -+ lea.4 TMP2_DN, %lo(__ocm_free_end)(DST_AN) -+ sub.4 #0, TMP2_DN, TMP_DN -+ jmple.f 2f -+ moveai DST_AN, #%hi(__data_begin) -+ lea.4 TMP_DN, %lo(__data_begin)(DST_AN) -+ moveai DST_AN, #%hi(OCMSTART) -+ lea.4 TMP2_DN, %lo(OCMSTART)(DST_AN) -+ sub.4 TMP_DN, TMP_DN, TMP2_DN -+ lsr.4 TMP_DN, TMP_DN, #15 -+ lsl.4 TMP_DN, #1, TMP_DN -+ moveai DST_AN, #%hi(OCMC_BASE) -+ add.4 OCMC_BANK_MASK(DST_AN), #-1, TMP_DN -+ pipe_flush 0 -+2: -+; -+; Load .ocm_text -+; -+ moveai DST_AN, #%hi(__ocm_text_run_end) -+ lea.4 TMP_DN, %lo(__ocm_text_run_end)(DST_AN) -+ moveai DST_AN, #%hi(__ocm_text_run_begin) -+ lea.4 DST_AN, %lo(__ocm_text_run_begin)(DST_AN) -+ moveai SRC_AN, #%hi(__ocm_text_load_begin) -+ lea.4 SRC_AN, %lo(__ocm_text_load_begin)(SRC_AN) -+ jmpt.t 2f -+ -+1: move.4 (DST_AN)4++, (SRC_AN)4++ -+ -+2: sub.4 #0, DST_AN, TMP_DN -+ jmpne.t 1b -+; -+; Load .syscall_text -+; -+ moveai DST_AN, #%hi(__syscall_text_run_end) -+ lea.4 TMP_DN, %lo(__syscall_text_run_end)(DST_AN) -+ moveai DST_AN, #%hi(__syscall_text_run_begin) -+ lea.4 DST_AN, %lo(__syscall_text_run_begin)(DST_AN) -+ moveai SRC_AN, #%hi(__syscall_text_load_begin) -+ lea.4 SRC_AN, %lo(__syscall_text_load_begin)(SRC_AN) -+ jmpt.t 2f -+ -+1: move.4 (DST_AN)4++, (SRC_AN)4++ -+ -+2: sub.4 #0, DST_AN, TMP_DN -+ jmpne.t 1b -+ -+; -+; Load .ocm_data -+; -+ moveai DST_AN, #%hi(__ocm_data_run_end) -+ lea.4 TMP_DN, %lo(__ocm_data_run_end)(DST_AN) -+ moveai DST_AN, #%hi(__ocm_data_run_begin) -+ lea.4 DST_AN, %lo(__ocm_data_run_begin)(DST_AN) -+ moveai SRC_AN, #%hi(__ocm_data_load_begin) -+ lea.4 SRC_AN, %lo(__ocm_data_load_begin)(SRC_AN) -+ jmpt.t 2f -+ -+1: move.4 (DST_AN)4++, (SRC_AN)4++ -+ -+2: sub.4 #0, DST_AN, TMP_DN -+ jmpne.t 1b -+ -+; Clear .bss -+; -+ moveai SRC_AN, #%hi(_ebss) -+ lea.4 TMP_DN, %lo(_ebss)(SRC_AN) -+ moveai DST_AN, #%hi(_sbss) -+ lea.4 DST_AN, %lo(_sbss)(DST_AN) -+ jmpt.t 2f -+ -+1: move.4 (DST_AN)4++, #0 -+ -+2: sub.4 #0, DST_AN, TMP_DN -+ jmpne.t 1b -+ -+; save our parameter to devtree (after clearing .bss) -+ moveai DST_AN, #%hi(devtree) -+ lea.4 DST_AN, %lo(devtree)(DST_AN) -+ move.4 (DST_AN), PARAM_DN -+ -+ moveai sp, #%hi(init_thread_union) -+ lea.4 sp, %lo(init_thread_union)(sp) -+ movei TMP_DN, #ASM_THREAD_SIZE -+ add.4 sp, sp, TMP_DN -+ move.4 -4(sp)++, #0 ; nesting level = 0 -+ move.4 -4(sp)++, #1 ; KERNEL_THREAD -+ -+;; ip3k-elf-gdb backend now sets scratchpad3 to 1 when either continue -+;; or single step commands are issued. scratchpad3 is set to 0 when the -+;; debugger detaches from the board. -+ move.4 TMP_DN, scratchpad3 -+ lsl.4 TMP_DN, TMP_DN, #0x0 -+ jmpeq.f _jump_to_start_kernel -+_ok_to_set_break_points_in_linux: -+;; THREAD_STALL -+ move.4 mt_dbg_active_clr,#-1 -+;; stalling the threads isn't instantaneous.. need to flush the pipe. -+ pipe_flush 0 -+ pipe_flush 0 -+ -+_jump_to_start_kernel: -+ moveai SRC_AN, #%hi(start_kernel) -+ lea.4 SRC_AN, %lo(start_kernel)(SRC_AN) -+ ret SRC_AN -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/init_task.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/init_task.c ---- linux-2.6.30.10/arch/ubicom32/kernel/init_task.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/init_task.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,62 @@ -+/* -+ * arch/ubicom32/kernel/init_task.c -+ * Ubicom32 architecture task initialization implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+///static struct fs_struct init_fs = INIT_FS; -+static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -+struct mm_struct init_mm = INIT_MM(init_mm); -+EXPORT_SYMBOL(init_mm); -+ -+/* -+ * Initial task structure. -+ * -+ * All other task structs will be allocated on slabs in fork.c -+ */ -+struct task_struct init_task = INIT_TASK(init_task); -+ -+EXPORT_SYMBOL(init_task); -+ -+/* -+ * Initial thread structure. -+ * -+ * We need to make sure that this is 8192-byte aligned due to the -+ * way process stacks are handled. This is done by having a special -+ * "init_task" linker map entry.. -+ */ -+union thread_union init_thread_union -+ __attribute__((__section__(".data.init_task"))) = -+ { INIT_THREAD_INFO(init_task) }; -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/irq.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/irq.c ---- linux-2.6.30.10/arch/ubicom32/kernel/irq.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/irq.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,597 @@ -+/* -+ * arch/ubicom32/kernel/irq.c -+ * Ubicom32 architecture IRQ support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * (C) Copyright 2007, Greg Ungerer -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+unsigned int irq_soft_avail; -+static struct irqaction ubicom32_reserve_action[NR_IRQS]; -+ -+#if !defined(CONFIG_DEBUG_IRQMEASURE) -+#define IRQ_DECLARE_MEASUREMENT -+#define IRQ_MEASUREMENT_START() -+#define IRQ_MEASUREMENT_END(irq) -+#else -+#define IRQ_DECLARE_MEASUREMENT \ -+ int __diff; \ -+ unsigned int __tstart; -+ -+#define IRQ_MEASUREMENT_START() \ -+ __tstart = UBICOM32_IO_TIMER->sysval; -+ -+#define IRQ_MEASUREMENT_END(irq) \ -+ __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \ -+ irq_measurement_update((irq), __diff); -+ -+/* -+ * We keep track of the time spent in both irq_enter() -+ * and irq_exit(). -+ */ -+#define IRQ_WEIGHT 32 -+ -+struct irq_measurement { -+ volatile unsigned int min; -+ volatile unsigned int avg; -+ volatile unsigned int max; -+}; -+ -+static DEFINE_SPINLOCK(irq_measurement_lock); -+ -+/* -+ * Add 1 in for softirq (irq_exit()); -+ */ -+static struct irq_measurement irq_measurements[NR_IRQS + 1]; -+ -+/* -+ * irq_measurement_update() -+ * Update an entry in the measurement array for this irq. -+ */ -+static void irq_measurement_update(int irq, int sample) -+{ -+ struct irq_measurement *im = &irq_measurements[irq]; -+ spin_lock(&irq_measurement_lock); -+ if ((im->min == 0) || (im->min > sample)) { -+ im->min = sample; -+ } -+ if (im->max < sample) { -+ im->max = sample; -+ } -+ im->avg = ((im->avg * (IRQ_WEIGHT - 1)) + sample) / IRQ_WEIGHT; -+ spin_unlock(&irq_measurement_lock); -+} -+#endif -+ -+/* -+ * irq_kernel_stack_check() -+ * See if the kernel stack is within STACK_WARN of the end. -+ */ -+static void irq_kernel_stack_check(int irq, struct pt_regs *regs) -+{ -+#ifdef CONFIG_DEBUG_STACKOVERFLOW -+ unsigned long sp; -+ -+ /* -+ * Make sure that we are not close to the top of the stack and thus -+ * can not really service this interrupt. -+ */ -+ asm volatile ( -+ "and.4 %0, SP, %1 \n\t" -+ : "=d" (sp) -+ : "d" (THREAD_SIZE - 1) -+ : "cc" -+ ); -+ -+ if (sp < (sizeof(struct thread_info) + STACK_WARN)) { -+ printk(KERN_WARNING -+ "cpu[%d]: possible overflow detected sp remain: %p, " -+ "irq: %d, regs: %p\n", -+ thread_get_self(), (void *)sp, irq, regs); -+ dump_stack(); -+ } -+ -+ if (sp < (sizeof(struct thread_info) + 16)) { -+ THREAD_STALL; -+ } -+#endif -+} -+ -+/* -+ * irq_get_lsb() -+ * Get the LSB set in value -+ */ -+static int irq_get_lsb(unsigned int value) -+{ -+ static unsigned char irq_bits[8] = { -+ 3, 0, 1, 0, 2, 0, 1, 0 -+ }; -+ u32_t nextbit = 0; -+ -+ value = (value >> nextbit) | (value << ((sizeof(value) * 8) - nextbit)); -+ -+ /* -+ * It's unlikely that we find that we execute the body of this while -+ * loop. 50% of the time we won't take this at all and then of the -+ * cases where we do about 50% of those we only execute once. -+ */ -+ if (!(value & 0xffff)) { -+ nextbit += 0x10; -+ value >>= 16; -+ } -+ -+ if (!(value & 0xff)) { -+ nextbit += 0x08; -+ value >>= 8; -+ } -+ -+ if (!(value & 0xf)) { -+ nextbit += 0x04; -+ value >>= 4; -+ } -+ -+ nextbit += irq_bits[value & 0x7]; -+ if (nextbit > 63) { -+ panic("nextbit out of range: %d\n", nextbit); -+ } -+ return nextbit; -+} -+ -+/* -+ * ubicom32_reserve_handler() -+ * Bogus handler associated with pre-reserved IRQ(s). -+ */ -+static irqreturn_t ubicom32_reserve_handler(int irq, void *dev_id) -+{ -+ BUG(); -+ return IRQ_HANDLED; -+} -+ -+/* -+ * __irq_disable_vector() -+ * Disable the interrupt by clearing the appropriate bit in the -+ * LDSR Mask Register. -+ */ -+static void __irq_disable_vector(unsigned int irq) -+{ -+ ldsr_disable_vector(irq); -+} -+ -+/* -+ * __irq_ack_vector() -+ * Acknowledge the specific interrupt by clearing the associate bit in -+ * hardware -+ */ -+static void __irq_ack_vector(unsigned int irq) -+{ -+ if (irq < 32) { -+ asm volatile ("move.4 INT_CLR0, %0" : : "d" (1 << irq)); -+ } else { -+ asm volatile ("move.4 INT_CLR1, %0" : : "d" (1 << (irq - 32))); -+ } -+} -+ -+/* -+ * __irq_enable_vector() -+ * Clean and then enable the interrupt by setting the appropriate bit in -+ * the LDSR Mask Register. -+ */ -+static void __irq_enable_vector(unsigned int irq) -+{ -+ /* -+ * Acknowledge, really clear the vector. -+ */ -+ __irq_ack_vector(irq); -+ ldsr_enable_vector(irq); -+} -+ -+/* -+ * __irq_mask_vector() -+ */ -+static void __irq_mask_vector(unsigned int irq) -+{ -+ ldsr_mask_vector(irq); -+} -+ -+/* -+ * __irq_unmask_vector() -+ */ -+static void __irq_unmask_vector(unsigned int irq) -+{ -+ ldsr_unmask_vector(irq); -+} -+ -+/* -+ * __irq_end_vector() -+ * Called once an interrupt is completed (reset the LDSR mask). -+ */ -+static void __irq_end_vector(unsigned int irq) -+{ -+ ldsr_unmask_vector(irq); -+} -+ -+#if defined(CONFIG_SMP) -+/* -+ * __irq_set_affinity() -+ * Set the cpu affinity for this interrupt. -+ * affinity container allocated at boot -+ */ -+static void __irq_set_affinity(unsigned int irq, const struct cpumask *dest) -+{ -+ smp_set_affinity(irq, dest); -+ cpumask_copy(irq_desc[irq].affinity, dest); -+} -+#endif -+ -+/* -+ * On-Chip Generic Interrupt function handling. -+ */ -+static struct irq_chip ubicom32_irq_chip = { -+ .name = "Ubicom32", -+ .startup = NULL, -+ .shutdown = NULL, -+ .enable = __irq_enable_vector, -+ .disable = __irq_disable_vector, -+ .ack = __irq_ack_vector, -+ .mask = __irq_mask_vector, -+ .unmask = __irq_unmask_vector, -+ .end = __irq_end_vector, -+#if defined(CONFIG_SMP) -+ .set_affinity = __irq_set_affinity, -+#endif -+}; -+ -+/* -+ * do_IRQ() -+ * Primary interface for handling IRQ() requests. -+ */ -+asmlinkage void do_IRQ(int irq, struct pt_regs *regs) -+{ -+ struct pt_regs *oldregs; -+ struct thread_info *ti = current_thread_info(); -+ -+ IRQ_DECLARE_MEASUREMENT; -+ -+ /* -+ * Mark that we are inside of an interrupt and -+ * that interrupts are disabled. -+ */ -+ oldregs = set_irq_regs(regs); -+ ti->interrupt_nesting++; -+ trace_hardirqs_off(); -+ irq_kernel_stack_check(irq, regs); -+ -+ /* -+ * Start the interrupt sequence -+ */ -+ irq_enter(); -+ -+ /* -+ * Execute the IRQ handler and any pending SoftIRQ requests. -+ */ -+ BUG_ON(!irqs_disabled()); -+ IRQ_MEASUREMENT_START(); -+ __do_IRQ(irq); -+ IRQ_MEASUREMENT_END(irq); -+ BUG_ON(!irqs_disabled()); -+ -+ /* -+ * TODO: Since IRQ's are disabled when calling irq_exit() -+ * modify Kconfig to set __ARCH_IRQ_EXIT_IRQS_DISABLED flag. -+ * This will slightly improve performance by enabling -+ * softirq handling to avoid disabling/disabled interrupts. -+ */ -+ IRQ_MEASUREMENT_START(); -+ irq_exit(); -+ IRQ_MEASUREMENT_END(NR_IRQS); -+ BUG_ON(!irqs_disabled()); -+ -+ /* -+ * Outside of an interrupt (or nested exit). -+ */ -+ set_irq_regs(oldregs); -+ trace_hardirqs_on(); -+ ti->interrupt_nesting--; -+} -+ -+/* -+ * irq_soft_alloc() -+ * Allocate a soft IRQ. -+ */ -+int irq_soft_alloc(unsigned int *soft) -+{ -+ if (irq_soft_avail == 0) { -+ printk(KERN_NOTICE "no soft irqs to allocate\n"); -+ return -EFAULT; -+ } -+ -+ *soft = irq_get_lsb(irq_soft_avail); -+ irq_soft_avail &= ~(1 << *soft); -+ return 0; -+} -+ -+/* -+ * ack_bad_irq() -+ * Called to handle an bad irq request. -+ */ -+void ack_bad_irq(unsigned int irq) -+{ -+ printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq); -+ __irq_end_vector(irq); -+} -+ -+/* -+ * show_interrupts() -+ * Return a string that displays the state of each of the interrupts. -+ */ -+int show_interrupts(struct seq_file *p, void *v) -+{ -+ struct irqaction *ap; -+ int irq = *((loff_t *) v); -+ int j; -+ -+ if (irq >= NR_IRQS) { -+ return 0; -+ } -+ -+ if (irq == 0) { -+ seq_puts(p, " "); -+ for_each_online_cpu(j) { -+ seq_printf(p, "CPU%d ", j); -+ } -+ seq_putc(p, '\n'); -+ } -+ -+ ap = irq_desc[irq].action; -+ if (ap) { -+ seq_printf(p, "%3d: ", irq); -+ for_each_online_cpu(j) { -+ seq_printf(p, "%10u ", kstat_irqs_cpu(irq, j)); -+ } -+ seq_printf(p, "%14s ", irq_desc[irq].chip->name); -+ seq_printf(p, "%s", ap->name); -+ for (ap = ap->next; ap; ap = ap->next) { -+ seq_printf(p, ", %s", ap->name); -+ } -+ seq_putc(p, '\n'); -+ } -+ return 0; -+} -+ -+#if defined(CONFIG_DEBUG_IRQMEASURE) -+static unsigned int irq_cycles_to_micro(unsigned int cycles, unsigned int frequency) -+{ -+ unsigned int micro = (cycles / (frequency / 1000000)); -+ return micro; -+} -+ -+/* -+ * irq_measurement_show() -+ * Print out the min, avg, max values for each IRQ -+ * -+ * By request, the max value is reset after each dump. -+ */ -+static int irq_measurement_show(struct seq_file *p, void *v) -+{ -+ struct irqaction *ap; -+ unsigned int freq = processor_frequency(); -+ int irq = *((loff_t *) v); -+ -+ -+ if (irq == 0) { -+ seq_puts(p, "\tmin\tavg\tmax\t(micro-seconds)\n"); -+ } -+ -+ if (irq > NR_IRQS) { -+ return 0; -+ } -+ -+ if (irq == NR_IRQS) { -+ unsigned int min, avg, max; -+ spin_lock(&irq_measurement_lock); -+ min = irq_cycles_to_micro(irq_measurements[irq].min, freq); -+ avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq); -+ max = irq_cycles_to_micro(irq_measurements[irq].max, freq); -+ irq_measurements[irq].max = 0; -+ spin_unlock(&irq_measurement_lock); -+ seq_printf(p, " \t%u\t%u\t%u\tsoftirq\n", min, avg, max); -+ return 0; -+ } -+ -+ ap = irq_desc[irq].action; -+ if (ap) { -+ unsigned int min, avg, max; -+ spin_lock(&irq_measurement_lock); -+ min = irq_cycles_to_micro(irq_measurements[irq].min, freq); -+ avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq); -+ max = irq_cycles_to_micro(irq_measurements[irq].max, freq); -+ irq_measurements[irq].max = 0; -+ spin_unlock(&irq_measurement_lock); -+ seq_printf(p, "%2u:\t%u\t%u\t%u\t%s\n", irq, min, avg, max, ap->name); -+ } -+ return 0; -+} -+ -+static void *irq_measurement_start(struct seq_file *f, loff_t *pos) -+{ -+ return (*pos <= NR_IRQS) ? pos : NULL; -+} -+ -+static void *irq_measurement_next(struct seq_file *f, void *v, loff_t *pos) -+{ -+ (*pos)++; -+ if (*pos > NR_IRQS) -+ return NULL; -+ return pos; -+} -+ -+static void irq_measurement_stop(struct seq_file *f, void *v) -+{ -+ /* Nothing to do */ -+} -+ -+static const struct seq_operations irq_measurement_seq_ops = { -+ .start = irq_measurement_start, -+ .next = irq_measurement_next, -+ .stop = irq_measurement_stop, -+ .show = irq_measurement_show, -+}; -+ -+static int irq_measurement_open(struct inode *inode, struct file *filp) -+{ -+ return seq_open(filp, &irq_measurement_seq_ops); -+} -+ -+static const struct file_operations irq_measurement_fops = { -+ .open = irq_measurement_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+static int __init irq_measurement_init(void) -+{ -+ proc_create("irq_measurements", 0, NULL, &irq_measurement_fops); -+ return 0; -+} -+module_init(irq_measurement_init); -+#endif -+ -+/* -+ * init_IRQ(void) -+ * Initialize the on-chip IRQ subsystem. -+ */ -+void __init init_IRQ(void) -+{ -+ int irq; -+ struct devtree_node *p = NULL; -+ struct devtree_node *iter = NULL; -+ unsigned int mask = 0; -+ unsigned int reserved = 0; -+ -+ /* -+ * Pull out the list of software interrupts that are avialable to -+ * Linux and provide an allocation function for them. The first -+ * 24 interrupts of INT0 are software interrupts. -+ */ -+ irq_soft_avail = 0; -+ if (processor_interrupts(&irq_soft_avail, NULL) < 0) { -+ printk(KERN_WARNING "No Soft IRQ(s) available\n"); -+ } -+ irq_soft_avail &= ((1 << 24) - 1); -+ -+ /* -+ * Initialize all of the on-chip interrupt handling -+ * to use a common set of interrupt functions. -+ */ -+ for (irq = 0; irq < NR_IRQS; irq++) { -+ irq_desc[irq].status = IRQ_DISABLED; -+ irq_desc[irq].action = NULL; -+ irq_desc[irq].depth = 1; -+ set_irq_chip(irq, &ubicom32_irq_chip); -+ } -+ -+ /* -+ * The sendirq of a devnode is not registered within Linux but instead -+ * is used by the software I/O thread. These interrupts are reserved. -+ * The recvirq is used by Linux and registered by a device driver, these -+ * are not reserved. -+ * -+ * recvirq(s) that are in the software interrupt range are not supposed -+ * to be marked as reserved. We track this while we scan the device -+ * nodes. -+ */ -+ p = devtree_find_next(&iter); -+ while (p) { -+ unsigned char sendirq, recvirq; -+ devtree_irq(p, &sendirq, &recvirq); -+ -+ /* -+ * If the sendirq is valid, mark that irq as taken by the -+ * devtree node. -+ */ -+ if (sendirq < NR_IRQS) { -+ ubicom32_reserve_action[sendirq].handler = -+ ubicom32_reserve_handler; -+ ubicom32_reserve_action[sendirq].name = p->name; -+ irq_desc[sendirq].action = -+ &ubicom32_reserve_action[sendirq]; -+ mask |= (1 << sendirq); -+ } -+ -+ /* -+ * Track the relevant recieve IRQ(s) -+ */ -+ if (recvirq < 24) { -+ mask |= (1 << recvirq); -+ } -+ -+ /* -+ * Move to the next node. -+ */ -+ p = devtree_find_next(&iter); -+ } -+ -+ /* -+ * Remove these bits from the irq_soft_avail list and then use the -+ * result as the list of pre-reserved IRQ(s). -+ */ -+ reserved = ~irq_soft_avail & ~mask; -+ for (irq = 0; irq < 24; irq++) { -+ if ((reserved & (1 << irq))) { -+ ubicom32_reserve_action[irq].handler = -+ ubicom32_reserve_handler; -+ ubicom32_reserve_action[irq].name = "reserved"; -+ irq_desc[irq].action = &ubicom32_reserve_action[irq]; -+ } -+ } -+ -+ /* -+ * Initialize the LDSR which is the Ubicom32 programmable -+ * interrupt controller. -+ */ -+ ldsr_init(); -+ -+ /* -+ * The Ubicom trap code needs a 2nd init after IRQ(s) are setup. -+ */ -+ trap_init_interrupt(); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/ldsr.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/ldsr.c ---- linux-2.6.30.10/arch/ubicom32/kernel/ldsr.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/ldsr.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,1185 @@ -+/* -+ * arch/ubicom32/kernel/ldsr.c -+ * Ubicom32 architecture Linux Device Services Driver Interface -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * -+ * NOTES: -+ * -+ * The LDSR is a programmable interrupt controller that is written in software. -+ * It emulates the behavior of an pic by fielding the interrupts, choosing a -+ * victim thread to take the interrupt and forcing that thread to take a context -+ * switch to the appropriate interrupt handler. -+ * -+ * Because traps are treated as just a special class of interrupts, the LDSR -+ * also handles the processing of traps. -+ * -+ * Because we compile Linux both UP and SMP, we need the LDSR to use -+ * architectural locking that is not "compiled out" when compiling UP. For now, -+ * we use the single atomic bit lock. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * One can not print from the LDSR so the best we can do is -+ * check a condition and stall all of the threads. -+ */ -+ -+// #define DEBUG_LDSR 1 -+#if defined(DEBUG_LDSR) -+#define DEBUG_ASSERT(cond) \ -+ if (!(cond)) { \ -+ THREAD_STALL; \ -+ } -+#else -+#define DEBUG_ASSERT(cond) -+#endif -+ -+/* -+ * Make global so that we can use it in the RFI code in assembly. -+ */ -+unsigned int ldsr_soft_irq_mask; -+EXPORT_SYMBOL(ldsr_soft_irq_mask); -+ -+static unsigned int ldsr_suspend_mask; -+static unsigned int ldsr_soft_irq; -+static unsigned int ldsr_stack_space[1024]; -+ -+static struct ldsr_register_bank { -+ volatile unsigned int enabled0; -+ volatile unsigned int enabled1; -+ volatile unsigned int mask0; -+ volatile unsigned int mask1; -+ unsigned int total; -+ unsigned int retry; -+ unsigned int backout; -+} ldsr_interrupt; -+ -+/* -+ * Which thread/cpu are we? -+ */ -+static int ldsr_tid = -1; -+ -+#if defined(CONFIG_IRQSTACKS) -+/* -+ * per-CPU IRQ stacks (thread information and stack) -+ * -+ * NOTE: Do not use DEFINE_PER_CPU() as it makes it harder -+ * to find the location of ctx from assembly language. -+ */ -+union irq_ctx { -+ struct thread_info tinfo; -+ u32 stack[THREAD_SIZE/sizeof(u32)]; -+}; -+static union irq_ctx *percpu_irq_ctxs[NR_CPUS]; -+ -+/* -+ * Storage for the interrupt stack. -+ */ -+#if !defined(CONFIG_IRQSTACKS_USEOCM) -+static char percpu_irq_stacks[(NR_CPUS * THREAD_SIZE) + (THREAD_SIZE - 1)]; -+#else -+/* -+ * For OCM, the linker will ensure that space is allocated for the stack -+ * see (vmlinux.lds.S) -+ */ -+static char percpu_irq_stacks[]; -+#endif -+ -+#endif -+ -+/* -+ * Save trap IRQ because we need to un-suspend if it gets set. -+ */ -+static unsigned int ldsr_trap_irq_mask; -+static unsigned int ldsr_trap_irq; -+ -+/* -+ * ret_from_interrupt_to_kernel -+ * Just restore the context and do nothing else. -+ */ -+asmlinkage void ret_from_interrupt_to_kernel(void)__attribute__((naked)); -+ -+/* -+ * ret_from_interrupt_to_user -+ * Call scheduler if needed. Just restore the context. -+ */ -+asmlinkage void ret_from_interrupt_to_user(void)__attribute__((naked)); -+ -+#ifdef DEBUG_LDSR -+u32_t old_sp, old_pc, old_a0, old_a5, old_a3; -+struct pt_regs copy_regs, *copy_save_area; -+#endif -+ -+int __user_mode(unsigned long sp) -+{ -+ -+ u32_t saved_stack_base = sp & ~(ASM_THREAD_SIZE - 1); -+#if defined(CONFIG_IRQSTACKS_USEOCM) -+ if ((union irq_ctx *)saved_stack_base == percpu_irq_ctxs[smp_processor_id()]) { -+ /* -+ * On the interrupt stack. -+ */ -+ return 0; -+ } -+#endif -+ -+ if (!(u32_t)current) { -+ return 0; -+ } -+ return saved_stack_base != ((u32_t)current->stack); -+} -+ -+/* -+ * ldsr_lock_release() -+ * Release the LDSR lock. -+ */ -+static void ldsr_lock_release(void) -+{ -+ UBICOM32_UNLOCK(LDSR_LOCK_BIT); -+} -+ -+/* -+ * ldsr_lock_acquire() -+ * Acquire the LDSR lock, spin if not available. -+ */ -+static void ldsr_lock_acquire(void) -+{ -+ UBICOM32_LOCK(LDSR_LOCK_BIT); -+} -+ -+/* -+ * ldsr_thread_irq_disable() -+ * Disable interrupts for the specified thread. -+ */ -+static void ldsr_thread_irq_disable(unsigned int tid) -+{ -+ unsigned int mask = (1 << tid); -+ -+ asm volatile ( -+ " or.4 scratchpad1, scratchpad1, %0 \n\t" -+ : -+ : "d"(mask) -+ : "cc" -+ ); -+} -+ -+/* -+ * ldsr_thread_get_interrupts() -+ * Get the interrupt state for all threads. -+ */ -+static unsigned long ldsr_thread_get_interrupts(void) -+{ -+ unsigned long ret = 0; -+ asm volatile ( -+ " move.4 %0, scratchpad1 \n\t" -+ : "=r" (ret) -+ : -+ ); -+ return ret; -+} -+ -+/* -+ * ldsr_emulate_and_run() -+ * Emulate the instruction and then set the thread to run. -+ */ -+static void ldsr_emulate_and_run(unsigned int tid) -+{ -+ unsigned int thread_mask = (1 << tid); -+ u32_t write_csr = (tid << 15) | (1 << 14); -+ -+ /* -+ * Emulate the unaligned access. -+ */ -+ unaligned_emulate(tid); -+ -+ /* -+ * Get the thread back in a running state. -+ */ -+ asm volatile ( -+ " setcsr %0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " move.4 trap_cause, #0 \n\t" /* Clear the trap cause -+ * register */ -+ " setcsr #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " move.4 mt_dbg_active_set, %1 \n\t" /* Activate thread even if -+ * in dbg/fault state */ -+ " move.4 mt_active_set, %1 \n\t" /* Restart target -+ * thread. */ -+ : -+ : "r" (write_csr), "d" (thread_mask) -+ : "cc" -+ ); -+ thread_enable_mask(thread_mask); -+} -+ -+/* -+ * ldsr_preemptive_context_save() -+ * save thread context from another hardware thread. The other thread must -+ * be stalled. -+ */ -+static inline void ldsr_preemptive_context_save(u32_t thread, -+ struct pt_regs *regs) -+{ -+ /* -+ * Save the current state of the specified thread -+ */ -+ asm volatile ( -+ " move.4 a3, %0 \n\t" -+ -+ /* set src1 from the target thread */ -+ " move.4 csr, %1 \n\t" -+ " setcsr_flush 0 \n\t" -+ " setcsr_flush 0 \n\t" -+ -+ /* copy state from the other thread */ -+ " move.4 "D(PT_D0)"(a3), d0 \n\t" -+ " move.4 "D(PT_D1)"(a3), d1 \n\t" -+ " move.4 "D(PT_D2)"(a3), d2 \n\t" -+ " move.4 "D(PT_D3)"(a3), d3 \n\t" -+ " move.4 "D(PT_D4)"(a3), d4 \n\t" -+ " move.4 "D(PT_D5)"(a3), d5 \n\t" -+ " move.4 "D(PT_D6)"(a3), d6 \n\t" -+ " move.4 "D(PT_D7)"(a3), d7 \n\t" -+ " move.4 "D(PT_D8)"(a3), d8 \n\t" -+ " move.4 "D(PT_D9)"(a3), d9 \n\t" -+ " move.4 "D(PT_D10)"(a3), d10 \n\t" -+ " move.4 "D(PT_D11)"(a3), d11 \n\t" -+ " move.4 "D(PT_D12)"(a3), d12 \n\t" -+ " move.4 "D(PT_D13)"(a3), d13 \n\t" -+ " move.4 "D(PT_D14)"(a3), d14 \n\t" -+ " move.4 "D(PT_D15)"(a3), d15 \n\t" -+ " move.4 "D(PT_A0)"(a3), a0 \n\t" -+ " move.4 "D(PT_A1)"(a3), a1 \n\t" -+ " move.4 "D(PT_A2)"(a3), a2 \n\t" -+ " move.4 "D(PT_A3)"(a3), a3 \n\t" -+ " move.4 "D(PT_A4)"(a3), a4 \n\t" -+ " move.4 "D(PT_A5)"(a3), a5 \n\t" -+ " move.4 "D(PT_A6)"(a3), a6 \n\t" -+ " move.4 "D(PT_SP)"(a3), a7 \n\t" -+ " move.4 "D(PT_ACC0HI)"(a3), acc0_hi \n\t" -+ " move.4 "D(PT_ACC0LO)"(a3), acc0_lo \n\t" -+ " move.4 "D(PT_MAC_RC16)"(a3), mac_rc16 \n\t" -+ " move.4 "D(PT_ACC1HI)"(a3), acc1_hi \n\t" -+ " move.4 "D(PT_ACC1LO)"(a3), acc1_lo \n\t" -+ " move.4 "D(PT_SOURCE3)"(a3), source3 \n\t" -+ " move.4 "D(PT_INST_CNT)"(a3), inst_cnt \n\t" -+ " move.4 "D(PT_CSR)"(a3), csr \n\t" -+ " move.4 "D(PT_DUMMY_UNUSED)"(a3), #0 \n\t" -+ " move.4 "D(PT_INT_MASK0)"(a3), int_mask0 \n\t" -+ " move.4 "D(PT_INT_MASK1)"(a3), int_mask1 \n\t" -+ " move.4 "D(PT_TRAP_CAUSE)"(a3), trap_cause \n\t" -+ " move.4 "D(PT_PC)"(a3), pc \n\t" -+ " move.4 "D(PT_PREVIOUS_PC)"(a3), previous_pc \n\t" -+ /* disable csr thread select */ -+ " movei csr, #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ : -+ : "r" (regs->dn), "d" ((thread << 9) | (1 << 8)) -+ : "a3" -+ ); -+} -+ -+/* -+ * ldsr_rotate_threads() -+ * Simple round robin algorithm for choosing the next cpu -+ */ -+static int ldsr_rotate_threads(unsigned long cpus) -+{ -+ static unsigned char ldsr_bits[8] = { -+ 3, 0, 1, 0, 2, 0, 1, 0 -+ }; -+ -+ static int nextbit; -+ int thisbit; -+ -+ /* -+ * Move the interrupts down so that we consider interrupts from where -+ * we left off, then take the interrupts we would lose and move them -+ * to the top half of the interrupts value. -+ */ -+ cpus = (cpus >> nextbit) | (cpus << ((sizeof(cpus) * 8) - nextbit)); -+ -+ /* -+ * 50% of the time we won't take this at all and then of the cases where -+ * we do about 50% of those we only execute once. -+ */ -+ if (!(cpus & 0xffff)) { -+ nextbit += 16; -+ cpus >>= 16; -+ } -+ -+ if (!(cpus & 0xff)) { -+ nextbit += 8; -+ cpus >>= 8; -+ } -+ -+ if (!(cpus & 0xf)) { -+ nextbit += 4; -+ cpus >>= 4; -+ } -+ -+ nextbit += ldsr_bits[cpus & 0x7]; -+ thisbit = (nextbit & ((sizeof(cpus) * 8) - 1)); -+ nextbit = (thisbit + 1) & ((sizeof(cpus) * 8) - 1); -+ DEBUG_ASSERT(thisbit < THREAD_ARCHITECTURAL_MAX); -+ return thisbit; -+} -+ -+/* -+ * ldsr_rotate_interrupts() -+ * Get rotating next set bit value. -+ */ -+static int ldsr_rotate_interrupts(unsigned long long interrupts) -+{ -+ static unsigned char ldsr_bits[8] = { -+ 3, 0, 1, 0, 2, 0, 1, 0 -+ }; -+ -+ static int nextbit; -+ int thisbit; -+ -+ /* -+ * Move the interrupts down so that we consider interrupts from where -+ * we left off, then take the interrupts we would lose and move them -+ * to the top half of the interrupts value. -+ */ -+ interrupts = (interrupts >> nextbit) | -+ (interrupts << ((sizeof(interrupts) * 8) - nextbit)); -+ -+ /* -+ * 50% of the time we won't take this at all and then of the cases where -+ * we do about 50% of those we only execute once. -+ */ -+ if (!(interrupts & 0xffffffff)) { -+ nextbit += 32; -+ interrupts >>= 32; -+ } -+ -+ if (!(interrupts & 0xffff)) { -+ nextbit += 16; -+ interrupts >>= 16; -+ } -+ -+ if (!(interrupts & 0xff)) { -+ nextbit += 8; -+ interrupts >>= 8; -+ } -+ -+ if (!(interrupts & 0xf)) { -+ nextbit += 4; -+ interrupts >>= 4; -+ } -+ -+ nextbit += ldsr_bits[interrupts & 0x7]; -+ thisbit = (nextbit & ((sizeof(interrupts) * 8) - 1)); -+ nextbit = (thisbit + 1) & ((sizeof(interrupts) * 8) - 1); -+ -+ DEBUG_ASSERT(thisbit < (sizeof(interrupts) * 8)); -+ return thisbit; -+} -+ -+/* -+ * ldsr_backout_or_irq() -+ * -+ * One way or the other this interrupt is not being -+ * processed, make sure that it is reset. We are -+ * not going to call irq_end_vector() so unmask the -+ * interrupt. -+ */ -+static void ldsr_backout_of_irq(int vector, unsigned long tid_mask) -+{ -+#if defined(CONFIG_SMP) -+ if (unlikely(vector == smp_ipi_irq)) { -+ smp_reset_ipi(tid_mask); -+ } -+#endif -+ ldsr_unmask_vector(vector); -+ ldsr_interrupt.backout++; -+} -+ -+#if defined(CONFIG_IRQSTACKS) -+/* -+ * ldsr_choose_savearea_and_returnvec() -+ * Test our current state (user, kernel, interrupt) and set things up. -+ * -+ * This version of the function uses 3 stacks and nests interrupts -+ * on the interrupt stack. -+ */ -+static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec) -+{ -+ struct pt_regs *save_area; -+ u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1); -+ struct thread_info * ti= (struct thread_info *)sw_ksp[tid]; -+ -+#if defined(CONFIG_SMP) -+ union irq_ctx *icp = percpu_irq_ctxs[tid]; -+#else -+ union irq_ctx *icp = percpu_irq_ctxs[0]; -+#endif -+ -+ if (masked_linux_sp == (u32_t)icp) { -+ /* -+ * Fault/Interrupt occurred while on the interrupt stack. -+ */ -+ save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8); -+ *pvec = (u32_t)(&ret_from_interrupt_to_kernel); -+ } else { -+ /* -+ * Fault/Interrupt occurred while on user/kernel stack. This is a new -+ * first use of the interrupt stack. -+ */ -+ save_area = (struct pt_regs *) ((char *)icp + sizeof(icp->stack) - sizeof(struct pt_regs) - 8); -+ if (masked_linux_sp == (u32_t)ti) { -+ *pvec = (u32_t)(&ret_from_interrupt_to_kernel); -+ } else { -+ *pvec = (u32_t)(&ret_from_interrupt_to_user); -+ } -+ -+ /* -+ * Because the softirq code will execute on the "interrupt" stack, we -+ * need to maintain the knowledge of what "task" was executing on the -+ * cpu. This is done by copying the thread_info->task from the cpu -+ * we are about to context switch into the interrupt contexts thread_info -+ * structure. -+ */ -+ icp->tinfo.task = ti->task; -+ icp->tinfo.preempt_count = -+ (icp->tinfo.preempt_count & ~SOFTIRQ_MASK) | -+ (ti->preempt_count & SOFTIRQ_MASK); -+ icp->tinfo.interrupt_nesting = 0; -+ } -+ save_area->nesting_level = icp->tinfo.interrupt_nesting; -+ return save_area; -+} -+ -+#else -+/* -+ * ldsr_choose_savearea_and_returnvec() -+ * Test our current state (user, kernel, interrupt) and set things up. -+ * -+ * The version of the function uses just the user & kernel stack and -+ * nests interrupts on the existing kernel stack. -+ */ -+static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec) -+{ -+ struct pt_regs *save_area; -+ u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1); -+ struct thread_info *ti = (struct thread_info *)sw_ksp[tid]; -+ -+ if (masked_linux_sp == (u32_t)ti) { -+ /* -+ * Fault/Interrupt occurred while on the kernel stack. -+ */ -+ save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8); -+ *pvec = (u32_t) (&ret_from_interrupt_to_kernel); -+ } else { -+ /* -+ * Fault/Interrupt occurred while on user stack. -+ */ -+ ti->interrupt_nesting = 0; -+ save_area = (struct pt_regs *)((u32_t)ti + THREAD_SIZE - sizeof(struct pt_regs) - 8); -+ *pvec = (u32_t) (&ret_from_interrupt_to_user); -+ } -+ save_area->nesting_level = ti->interrupt_nesting; -+ return save_area; -+} -+#endif -+ -+/* -+ * ldsr_ctxsw_thread() -+ * Context switch a mainline thread to execute do_IRQ() for the specified -+ * vector. -+ */ -+static void ldsr_ctxsw_thread(int vector, thread_t tid) -+{ -+ u32_t linux_sp; -+ u32_t return_vector; -+ struct pt_regs *save_area, *regs; -+ u32_t thread_mask = (1 << tid); -+ u32_t read_csr = ((tid << 9) | (1 << 8)); -+ u32_t write_csr = (tid << 15) | (1 << 14); -+ u32_t interrupt_vector = (u32_t)(&do_IRQ); -+ -+ unsigned int frame_type = UBICOM32_FRAME_TYPE_INTERRUPT; -+ -+ -+ DEBUG_ASSERT(!thread_is_enabled(tid)); -+ -+ /* -+ * Acquire the necessary global and per thread locks for tid. -+ * As a side effect, we ensure that the thread has not trapped -+ * and return true if it has. -+ */ -+ if (unlikely(thread_is_trapped(tid))) { -+ /* -+ * Read the trap cause, the sp and clear the MT_TRAP bits. -+ */ -+ unsigned int cause; -+ asm volatile ( -+ " setcsr %3 \n\t" -+ " setcsr_flush 0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " move.4 %0, TRAP_CAUSE \n\t" -+ " move.4 %1, SP \n\t" -+ " setcsr #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " move.4 MT_BREAK_CLR, %2\n\t" -+ " move.4 MT_TRAP_CLR, %2 \n\t" -+ : "=&r" (cause), "=&r" (linux_sp) -+ : "r" (thread_mask), "m" (read_csr) -+ ); -+ -+ ldsr_backout_of_irq(vector, (1 << tid)); -+ -+#if !defined(CONFIG_UNALIGNED_ACCESS_DISABLED) -+ /* -+ * See if the unaligned trap handler can deal with this. -+ * If so, emulate the instruction and then just restart -+ * the thread. -+ */ -+ if (unaligned_only(cause)) { -+#if defined(CONFIG_UNALIGNED_ACCESS_USERSPACE_ONLY) -+ /* -+ * Check if this is a kernel stack if so we will not -+ * handle the trap -+ */ -+ u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1); -+ if ((masked_linux_sp != (u32_t)sw_ksp[tid]) && -+ unaligned_only(cause)) { -+ ldsr_emulate_and_run(tid); -+ return; -+ } -+#else -+ ldsr_emulate_and_run(tid); -+ return; -+#endif -+ -+ } -+#endif -+ -+ interrupt_vector = (u32_t)(&trap_handler); -+ frame_type = UBICOM32_FRAME_TYPE_TRAP; -+ } else { -+ /* -+ * Read the target thread's SP -+ */ -+ asm volatile ( -+ " setcsr %1 \n\t" -+ " setcsr_flush 0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " move.4 %0, SP \n\t" -+ " setcsr #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ : "=m" (linux_sp) -+ : "m" (read_csr) -+ ); -+ } -+ -+ /* -+ * We are delivering an interrupt, count it. -+ */ -+ ldsr_interrupt.total++; -+ -+ /* -+ * At this point, we will definitely force this thread to -+ * a new context, show its interrupts as disabled. -+ */ -+ ldsr_thread_irq_disable(tid); -+ -+ /* -+ * Test our current state (user, kernel, interrupt). Save the -+ * appropriate data and setup for the return. -+ */ -+ save_area = ldsr_choose_savearea_and_returnvec(tid, linux_sp, &return_vector); -+ -+ /* -+ * The pt_regs (save_area) contains the type of thread that we are dealing -+ * with (KERNEL/NORMAL) and is copied into each pt_regs area. We get this -+ * from the current tasks kernel pt_regs area that always exists at the -+ * top of the kernel stack. -+ */ -+ regs = (struct pt_regs *)((u32_t)sw_ksp[tid] + THREAD_SIZE - sizeof(struct pt_regs) - 8); -+ save_area->thread_type = regs->thread_type; -+ -+ /* -+ * Preserve the context of the Linux thread. -+ */ -+ ldsr_preemptive_context_save(tid, save_area); -+ -+ /* -+ * Load the fram_type into the save_area. -+ */ -+ save_area->frame_type = frame_type; -+ -+#ifdef CONFIG_STOP_ON_TRAP -+ /* -+ * Before we get backtrace and showing stacks working well, it sometimes -+ * helps to enter the debugger when a trap occurs before we change the -+ * thread to handle the fault. This optional code causes all threads to -+ * stop on every trap frame. One assumes that GDB connected via the -+ * mailbox interface will be used to recover from this state. -+ */ -+ if (frame_type == UBICOM32_FRAME_TYPE_TRAP) { -+ THREAD_STALL; -+ } -+#endif -+ -+#ifdef DEBUG_LDSR -+ copy_regs = *save_area; -+ copy_save_area = save_area; -+ -+ old_a0 = save_area->an[0]; -+ old_a3 = save_area->an[3]; -+ old_sp = save_area->an[7]; -+ old_a5 = save_area->an[5]; -+ old_pc = save_area->pc; -+#endif -+ -+ /* -+ * Now we have to switch the kernel thread to run do_IRQ function. -+ * Set pc to do_IRQ -+ * Set d0 to vector -+ * Set d1 to save_area. -+ * Set a5 to the proper return vector. -+ */ -+ asm volatile ( -+ " setcsr %0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " move.4 d0, %5 \n\t" /* d0 = 0 vector # */ -+ " move.4 d1, %1 \n\t" /* d1 = save_area */ -+ " move.4 sp, %1 \n\t" /* sp = save_area */ -+ " move.4 a5, %2 \n\t" /* a5 = return_vector */ -+ " move.4 pc, %3 \n\t" /* pc = do_IRQ routine. */ -+ " move.4 trap_cause, #0 \n\t" /* Clear the trap cause -+ * register */ -+ " setcsr #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " enable_kernel_ranges %4 \n\t" -+ " move.4 mt_dbg_active_set, %4 \n\t" /* Activate thread even if -+ * in dbg/fault state */ -+ " move.4 mt_active_set, %4 \n\t" /* Restart target -+ * thread. */ -+ : -+ : "r" (write_csr), "r" (save_area), -+ "r" (return_vector), "r" (interrupt_vector), -+ "d" (thread_mask), "r" (vector) -+ : "cc" -+ ); -+ thread_enable_mask(thread_mask); -+} -+ -+/* -+ * ldsr_deliver_interrupt() -+ * Deliver the interrupt to one of the threads or all of the threads. -+ */ -+static void ldsr_deliver_interrupt(int vector, -+ unsigned long deliver_to, -+ int all) -+{ -+ unsigned long disabled_threads; -+ unsigned long possible_threads; -+ unsigned long trapped_threads; -+ unsigned long global_locks; -+ -+ /* -+ * Disable all of the threads that we might want to send -+ * this interrupt to. -+ */ -+retry: -+ DEBUG_ASSERT(deliver_to); -+ thread_disable_mask(deliver_to); -+ -+ /* -+ * If any threads are in the trap state, we have to service the -+ * trap for those threads first. -+ */ -+ asm volatile ( -+ "move.4 %0, MT_TRAP \n\t" -+ : "=r" (trapped_threads) -+ : -+ ); -+ -+ trapped_threads &= deliver_to; -+ if (unlikely(trapped_threads)) { -+ /* -+ * all traps will be handled, so clear the trap bit before restarting any threads -+ */ -+ ubicom32_clear_interrupt(ldsr_trap_irq); -+ -+ /* -+ * Let the remaining untrapped threads, continue. -+ */ -+ deliver_to &= ~trapped_threads; -+ if (deliver_to) { -+ thread_enable_mask(deliver_to); -+ } -+ -+ /* -+ * For the trapped threads force them to handle -+ * a trap. -+ */ -+ while (trapped_threads) { -+ unsigned long which = ffz(~trapped_threads); -+ trapped_threads &= ~(1 << which); -+ ldsr_ctxsw_thread(vector, which); -+ } -+ return; -+ } -+ -+ /* -+ * Can we deliver an interrupt to any of the threads? -+ */ -+ disabled_threads = ldsr_thread_get_interrupts(); -+ possible_threads = deliver_to & ~disabled_threads; -+ if (unlikely(!possible_threads)) { -+#if defined(CONFIG_SMP) -+ /* -+ * In the SMP case, we can not wait because 1 cpu might be -+ * sending an IPI to another cpu which is currently blocked. -+ * The only way to ensure IPI delivery is to backout and -+ * keep trying. For SMP, we don't sleep until the interrupts -+ * are delivered. -+ */ -+ thread_enable_mask(deliver_to); -+ ldsr_backout_of_irq(vector, deliver_to); -+ return; -+#else -+ /* -+ * In the UP case, we have nothing to do so we should wait. -+ * -+ * Since the INT_MASK0 and INT_MASK1 are "re-loaded" before we -+ * suspend in the outer loop, we do not need to save them here. -+ * -+ * We test that we were awakened for our specific interrupts -+ * because the ldsr mask/unmask operations will force the ldsr -+ * awake even if the interrupt on the mainline thread is not -+ * completed. -+ */ -+ unsigned int scratch = 0; -+ thread_enable_mask(deliver_to); -+ asm volatile ( -+ " move.4 INT_MASK0, %1 \n\t" -+ " move.4 INT_MASK1, #0 \n\t" -+ -+ "1: suspend \n\t" -+ " move.4 %0, INT_STAT0 \n\t" -+ " and.4 %0, %0, %1 \n\t" -+ " jmpeq.f 1b \n\t" -+ -+ " move.4 INT_CLR0, %2 \n\t" -+ : "+r" (scratch) -+ : "d" (ldsr_suspend_mask), "r" (ldsr_soft_irq_mask) -+ : "cc" -+ ); -+ -+ /* -+ * This delay is sized to coincide with the time it takes a -+ * thread to complete the exit (see return_from_interrupt). -+ */ -+ ldsr_interrupt.retry++; -+ __delay(10); -+ goto retry; -+#endif -+ } -+ -+ /* -+ * If any of the global locks are held, we can not deliver any -+ * interrupts, we spin delay(10) and then try again. If our -+ * spinning becomes a bottle neck, we will need to suspend but for -+ * now lets just spin. -+ */ -+ asm volatile ( -+ "move.4 %0, scratchpad1 \n\t" -+ : "=r" (global_locks) -+ : -+ ); -+ if (unlikely(global_locks & 0xffff0000)) { -+ thread_enable_mask(deliver_to); -+ -+ /* -+ * This delay is sized to coincide with the average time it -+ * takes a thread to release a global lock. -+ */ -+ ldsr_interrupt.retry++; -+ __delay(10); -+ goto retry; -+ } -+ -+ /* -+ * Deliver to one cpu. -+ */ -+ if (!all) { -+ /* -+ * Find our victim and then enable everyone else. -+ */ -+ unsigned long victim = ldsr_rotate_threads(possible_threads); -+ DEBUG_ASSERT((deliver_to & (1 << victim))); -+ DEBUG_ASSERT((possible_threads & (1 << victim))); -+ -+ deliver_to &= ~(1 << victim); -+ if (deliver_to) { -+ thread_enable_mask(deliver_to); -+ } -+ ldsr_ctxsw_thread(vector, victim); -+ return; -+ } -+ -+ /* -+ * If we can't deliver to some threads, wake them -+ * back up and reset things to deliver to them. -+ */ -+ deliver_to &= ~possible_threads; -+ if (unlikely(deliver_to)) { -+ thread_enable_mask(deliver_to); -+ ldsr_backout_of_irq(vector, deliver_to); -+ } -+ -+ /* -+ * Deliver to all possible threads(s). -+ */ -+ while (possible_threads) { -+ unsigned long victim = ffz(~possible_threads); -+ possible_threads &= ~(1 << victim); -+ ldsr_ctxsw_thread(vector, victim); -+ } -+} -+ -+/* -+ * ldsr_thread() -+ * This thread acts as the interrupt controller for Linux. -+ */ -+static void ldsr_thread(void *arg) -+{ -+ int stat0; -+ int stat1; -+ int interrupt0; -+ int interrupt1; -+ long long interrupts; -+ unsigned long cpus; -+ -+#if !defined(CONFIG_SMP) -+ /* -+ * In a non-smp configuration, we can not use the cpu(s) arrays because -+ * there is not a 1-1 correspondence between cpus(s) and our threads. -+ * Thus we must get a local idea of the mainline threads and use the -+ * one and only 1 set as the victim. We do this once before the ldsr -+ * loop. -+ * -+ * In the SMP case, we will use the cpu(s) map to determine which cpu(s) -+ * are valid to send interrupts to. -+ */ -+ int victim = 0; -+ unsigned int mainline = thread_get_mainline(); -+ if (mainline == 0) { -+ panic("no mainline Linux threads to interrupt"); -+ return; -+ } -+ victim = ffz(~mainline); -+ cpus = (1 << victim); -+#endif -+ -+ while (1) { -+ /* -+ * If one changes this code not to reload the INT_MASK(s), you -+ * need to know that code in the lock waiting above does not -+ * reset the MASK registers back; so that code will need to be -+ * changed. -+ */ -+ ldsr_lock_acquire(); -+ asm volatile ( -+ " move.4 INT_MASK0, %0 \n\t" -+ " move.4 INT_MASK1, %1 \n\t" -+ : -+ : "U4" (ldsr_interrupt.mask0), "U4" (ldsr_interrupt.mask1) -+ ); -+ ldsr_lock_release(); -+ thread_suspend(); -+ -+ /* -+ * Read the interrupt status registers -+ */ -+ asm volatile ( -+ "move.4 %0, INT_STAT0 \n\t" -+ "move.4 %1, INT_STAT1 \n\t" -+ : "=r" (stat0), "=r" (stat1) -+ : -+ ); -+ -+ /* -+ * We only care about interrupts that we have been told to care -+ * about. The interrupt must be enabled, unmasked, and have -+ * occurred in the hardware. -+ */ -+ ldsr_lock_acquire(); -+ interrupt0 = ldsr_interrupt.enabled0 & -+ ldsr_interrupt.mask0 & stat0; -+ interrupt1 = ldsr_interrupt.enabled1 & -+ ldsr_interrupt.mask1 & stat1; -+ ldsr_lock_release(); -+ -+ /* -+ * For each interrupt in the "snapshot" we will mask the -+ * interrupt handle the interrupt (typically calling do_IRQ()). -+ * -+ * The interrupt is unmasked by desc->chip->end() function in -+ * the per chip generic interrupt handling code -+ * (arch/ubicom32/kernel/irq.c).8 -+ */ -+ interrupts = ((unsigned long long)interrupt1 << 32) | -+ interrupt0; -+ while (interrupts) { -+ int all = 0; -+ int vector = ldsr_rotate_interrupts(interrupts); -+ interrupts &= ~((unsigned long long)1 << vector); -+ -+ /* -+ * Now mask off this vector so that the LDSR ignores -+ * it until it is acknowledged. -+ */ -+ ldsr_mask_vector(vector); -+#if !defined(CONFIG_SMP) -+ ldsr_deliver_interrupt(vector, cpus, all); -+#else -+ cpus = smp_get_affinity(vector, &all); -+ if (!cpus) { -+ /* -+ * No CPU to deliver to so just leave -+ * the interrupt unmasked and increase -+ * the backout count. We will eventually -+ * return and deliver it again. -+ */ -+ ldsr_unmask_vector(vector); -+ ldsr_interrupt.backout++; -+ continue; -+ } -+ ldsr_deliver_interrupt(vector, cpus, all); -+#endif -+ } -+ } -+ -+ /* NOTREACHED */ -+} -+ -+/* -+ * ldsr_mask_vector() -+ * Temporarily mask the interrupt vector, turn off the bit in the mask -+ * register. -+ */ -+void ldsr_mask_vector(unsigned int vector) -+{ -+ unsigned int mask; -+ if (vector < 32) { -+ mask = ~(1 << vector); -+ ldsr_lock_acquire(); -+ ldsr_interrupt.mask0 &= mask; -+ ldsr_lock_release(); -+ thread_resume(ldsr_tid); -+ return; -+ } -+ -+ mask = ~(1 << (vector - 32)); -+ ldsr_lock_acquire(); -+ ldsr_interrupt.mask1 &= mask; -+ ldsr_lock_release(); -+ thread_resume(ldsr_tid); -+} -+ -+/* -+ * ldsr_unmask_vector() -+ * Unmask the interrupt vector so that it can be used, turn on the bit in -+ * the mask register. -+ * -+ * Because it is legal for the interrupt path to disable an interrupt, -+ * the unmasking code must ensure that disabled interrupts are not -+ * unmasked. -+ */ -+void ldsr_unmask_vector(unsigned int vector) -+{ -+ unsigned int mask; -+ if (vector < 32) { -+ mask = (1 << vector); -+ ldsr_lock_acquire(); -+ ldsr_interrupt.mask0 |= (mask & ldsr_interrupt.enabled0); -+ ldsr_lock_release(); -+ thread_resume(ldsr_tid); -+ return; -+ } -+ -+ mask = (1 << (vector - 32)); -+ ldsr_lock_acquire(); -+ ldsr_interrupt.mask1 |= (mask & ldsr_interrupt.enabled1); -+ ldsr_lock_release(); -+ thread_resume(ldsr_tid); -+} -+ -+/* -+ * ldsr_enable_vector() -+ * The LDSR implements an interrupt controller and has a local (to the -+ * LDSR) copy of its interrupt mask. -+ */ -+void ldsr_enable_vector(unsigned int vector) -+{ -+ unsigned int mask; -+ if (vector < 32) { -+ mask = (1 << vector); -+ ldsr_lock_acquire(); -+ ldsr_interrupt.enabled0 |= mask; -+ ldsr_interrupt.mask0 |= mask; -+ ldsr_lock_release(); -+ thread_resume(ldsr_tid); -+ return; -+ } -+ -+ mask = (1 << (vector - 32)); -+ ldsr_lock_acquire(); -+ ldsr_interrupt.enabled1 |= mask; -+ ldsr_interrupt.mask1 |= mask; -+ ldsr_lock_release(); -+ thread_resume(ldsr_tid); -+} -+ -+/* -+ * ldsr_disable_vector() -+ * The LDSR implements an interrupt controller and has a local (to the -+ * LDSR) copy of its interrupt mask. -+ */ -+void ldsr_disable_vector(unsigned int vector) -+{ -+ unsigned int mask; -+ -+ if (vector < 32) { -+ mask = ~(1 << vector); -+ ldsr_lock_acquire(); -+ ldsr_interrupt.enabled0 &= mask; -+ ldsr_interrupt.mask0 &= mask; -+ ldsr_lock_release(); -+ thread_resume(ldsr_tid); -+ return; -+ } -+ -+ mask = ~(1 << (vector - 32)); -+ ldsr_lock_acquire(); -+ ldsr_interrupt.enabled1 &= mask; -+ ldsr_interrupt.mask1 &= mask; -+ ldsr_lock_release(); -+ thread_resume(ldsr_tid); -+} -+ -+/* -+ * ldsr_get_threadid() -+ * Return the threadid of the LDSR thread. -+ */ -+thread_t ldsr_get_threadid(void) -+{ -+ return ldsr_tid; -+} -+ -+/* -+ * ldsr_set_trap_irq() -+ * Save away the trap Soft IRQ -+ * -+ * See the per thread lock suspend code above for an explination. -+ */ -+void ldsr_set_trap_irq(unsigned int irq) -+{ -+ ldsr_trap_irq = irq; -+ ldsr_trap_irq_mask = (1 << irq); -+ ldsr_suspend_mask |= ldsr_trap_irq_mask; -+} -+ -+/* -+ * ldsr_init() -+ * Initialize the LDSR (Interrupt Controller) -+ */ -+void ldsr_init(void) -+{ -+#if defined(CONFIG_IRQSTACKS) -+ int i; -+ union irq_ctx *icp; -+#endif -+ -+ void *stack_high = (void *)ldsr_stack_space; -+ stack_high += sizeof(ldsr_stack_space); -+ stack_high -= 8; -+ -+ -+ /* -+ * Obtain a soft IRQ to use -+ */ -+ if (irq_soft_alloc(&ldsr_soft_irq) < 0) { -+ panic("no software IRQ is available\n"); -+ return; -+ } -+ ldsr_soft_irq_mask |= (1 << ldsr_soft_irq); -+ ldsr_suspend_mask |= ldsr_soft_irq_mask; -+ -+ /* -+ * Now allocate and start the LDSR thread. -+ */ -+ ldsr_tid = thread_alloc(); -+ if (ldsr_tid < 0) { -+ panic("no thread available to run LDSR"); -+ return; -+ } -+ -+#if defined(CONFIG_IRQSTACKS) -+ /* -+ * Initialize the per-cpu irq thread_info structure that -+ * is at the top of each per-cpu irq stack. -+ */ -+ icp = (union irq_ctx *) -+ (((unsigned long)percpu_irq_stacks + (THREAD_SIZE - 1)) & ~(THREAD_SIZE - 1)); -+ for (i = 0; i < NR_CPUS; i++) { -+ struct thread_info *ti = &(icp->tinfo); -+ ti->task = NULL; -+ ti->exec_domain = NULL; -+ ti->cpu = i; -+ ti->preempt_count = 0; -+ ti->interrupt_nesting = 0; -+ percpu_irq_ctxs[i] = icp++; -+ } -+#endif -+ thread_start(ldsr_tid, ldsr_thread, NULL, -+ stack_high, THREAD_TYPE_NORMAL); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/Makefile linux-2.6.30.10-ubi/arch/ubicom32/kernel/Makefile ---- linux-2.6.30.10/arch/ubicom32/kernel/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/Makefile 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,64 @@ -+# -+# arch/ubicom32/kernel/Makefile -+# Main Makefile for the Ubicom32 arch directory. -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+ -+extra-y := head.o vmlinux.lds -+ -+obj-y += \ -+ devtree.o \ -+ dma.o \ -+ flat.o \ -+ init_task.o \ -+ irq.o \ -+ ldsr.o \ -+ os_node.o \ -+ process.o \ -+ processor.o \ -+ ptrace.o \ -+ setup.o \ -+ signal.o \ -+ stacktrace.o \ -+ sys_ubicom32.o \ -+ syscalltable.o \ -+ thread.o \ -+ time.o \ -+ traps.o \ -+ ubicom32_context_switch.o \ -+ ubicom32_ksyms.o \ -+ ubicom32_syscall.o \ -+ unaligned_trap.o -+ -+obj-$(CONFIG_MODULES) += module.o -+obj-$(CONFIG_COMEMPCI) += comempci.o -+obj-$(CONFIG_SMP) += smp.o topology.o -+obj-$(CONFIG_ACCESS_OK_CHECKS_ENABLED) += uaccess.o -+obj-$(CONFIG_GENERIC_CLOCKEVENTS) += timer_device.o -+obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += timer_broadcast.o -+ -+ifndef CONFIG_GENERIC_CLOCKEVENTS -+obj-y += timer_tick.o -+endif -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/module.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/module.c ---- linux-2.6.30.10/arch/ubicom32/kernel/module.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/module.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,463 @@ -+/* -+ * arch/ubicom32/kernel/module.c -+ * Ubicom32 architecture loadable module support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if 0 -+#define DEBUGP printk -+#else -+#define DEBUGP(fmt...) -+#endif -+ -+static void _module_free_ocm(struct module *mod) -+{ -+ printk(KERN_INFO "module arch cleanup %s: OCM instruction memory free " -+ " of %d @%p\n", mod->name, mod->arch.ocm_inst_size, -+ mod->arch.ocm_inst); -+ -+ if (mod->arch.ocm_inst) { -+ ocm_inst_free(mod->arch.ocm_inst); -+ mod->arch.ocm_inst = 0; -+ mod->arch.ocm_inst_size = 0; -+ } -+} -+ -+void *module_alloc(unsigned long size) -+{ -+ if (size == 0) -+ return NULL; -+ return vmalloc(size); -+} -+ -+ -+/* Free memory returned from module_alloc */ -+void module_free(struct module *mod, void *module_region) -+{ -+ vfree(module_region); -+ /* FIXME: If module_region == mod->init_region, trim exception -+ table entries. */ -+ -+ /* -+ * This is expected to be final module free, use this to prune the -+ * ocm -+ */ -+ if (module_region && module_region == mod->module_core) -+ _module_free_ocm(mod); -+ -+} -+ -+/* -+ * module_frob_arch_sections() -+ * Called from kernel/module.c allowing arch specific handling of -+ * sections/headers. -+ */ -+int module_frob_arch_sections(Elf_Ehdr *hdr, -+ Elf_Shdr *sechdrs, -+ char *secstrings, -+ struct module *mod) -+{ -+ Elf_Shdr *s, *sechdrs_end; -+ void *ocm_inst = NULL; -+ int ocm_inst_size = 0; -+ -+ /* -+ * Ubicom32 v3 and v4 are almost binary compatible but not completely. -+ * To be safe check that the module was compiled with the correct -march -+ * which is flags. -+ */ -+#ifdef CONFIG_UBICOM32_V4 -+ if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V4) { -+ printk(KERN_WARNING "Module %s was not compiled for " -+ "ubicom32v4, elf_flags:%x,\n", -+ mod->name, hdr->e_flags); -+ return -ENOEXEC; -+ } -+#elif defined CONFIG_UBICOM32_V3 -+ if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V3) { -+ printk(KERN_WARNING "Module %s was not compiled for " -+ "ubicom32v3, elf_flags:%x\n", -+ mod->name, hdr->e_flags); -+ return -ENOEXEC; -+ } -+#else -+#error Unknown/Unsupported ubicom32 architecture. -+#endif -+ -+ /* -+ * XXX: sechdrs are vmalloced in kernel/module.c -+ * and would be vfreed just after module is loaded, -+ * so we hack to keep the only information we needed -+ * in mod->arch to correctly free L1 I/D sram later. -+ * NOTE: this breaks the semantic of mod->arch structure. -+ */ -+ sechdrs_end = sechdrs + hdr->e_shnum; -+ for (s = sechdrs; s < sechdrs_end; ++s) { -+ if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0) -+ ocm_inst_size += s->sh_size; -+ } -+ -+ if (!ocm_inst_size) -+ return 0; -+ -+ ocm_inst = ocm_inst_alloc(ocm_inst_size, 0 /* internal */); -+ if (ocm_inst == NULL) { -+#ifdef CONFIG_OCM_MODULES_FALLBACK_TO_DDR -+ printk(KERN_WARNING -+ "module %s: OCM instruction memory allocation of %d" -+ "failed, fallback to DDR\n", mod->name, ocm_inst_size); -+ return 0; -+#else -+ printk(KERN_ERR -+ "module %s: OCM instruction memory allocation of %d" -+ "failed.\n", mod->name, ocm_inst_size); -+ return -ENOMEM; -+#endif -+ } -+ -+ mod->arch.ocm_inst = ocm_inst; -+ mod->arch.ocm_inst_size = ocm_inst_size; -+ -+ printk(KERN_INFO -+ "module %s: OCM instruction memory allocation of %d @%p\n", -+ mod->name, mod->arch.ocm_inst_size, mod->arch.ocm_inst); -+ -+ for (s = sechdrs; s < sechdrs_end; ++s) { -+ if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0) { -+ memcpy(ocm_inst, (void *)s->sh_addr, s->sh_size); -+ s->sh_flags &= ~SHF_ALLOC; -+ s->sh_addr = (unsigned long)ocm_inst; -+ ocm_inst += s->sh_size; -+ } -+ } -+ -+ return 0; -+} -+ -+int apply_relocate(Elf32_Shdr *sechdrs, -+ const char *strtab, -+ unsigned int symindex, -+ unsigned int relsec, -+ struct module *me) -+{ -+ DEBUGP("Invalid Applying relocate section %u to %u\n", relsec, -+ sechdrs[relsec].sh_info); -+ return -EINVAL; -+} -+ -+int apply_relocate_add(Elf32_Shdr *sechdrs, -+ const char *strtab, -+ unsigned int symindex, -+ unsigned int relsec, -+ struct module *me) -+{ -+ unsigned int i; -+ Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; -+ Elf32_Sym *sym; -+ uint32_t *location; -+ uint32_t insn; -+ -+ DEBUGP("Applying relocate_add section %u to %u\n", relsec, -+ sechdrs[relsec].sh_info); -+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { -+ uint32_t v; -+ const int elf32_rtype = ELF32_R_TYPE(rel[i].r_info); -+ -+ /* This is where to make the change */ -+ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr -+ + rel[i].r_offset; -+ /* This is the symbol it is referring to. Note that all -+ undefined symbols have been resolved. */ -+ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr -+ + ELF32_R_SYM(rel[i].r_info); -+ -+ v = rel[i].r_addend + sym->st_value; -+ -+ -+ switch (elf32_rtype) { -+ case R_UBICOM32_32: -+ { -+ /* -+ * Store the 32 bit relocation as is. -+ */ -+ *location = v; -+ break; -+ } -+ case R_UBICOM32_HI24: -+ { -+ /* -+ * 24 bit relocation that is part of the MOVEAI -+ * instruction. The 24 bits come from bits 7 - 30 of the -+ * relocation. Theses bits eventually get split into 2 -+ * fields in the instruction encoding. -+ * -+ * - Bits 7 - 27 of the relocation are encoded into bits -+ * 0 - 20 of the instruction. -+ * -+ * - Bits 28 - 30 of the relocation are encoded into -+ * bit 24 - 26 of the instruction. -+ */ -+ uint32_t valid24 = (v >> 7) & 0xffffff; -+ insn = *location; -+ -+ insn &= ~(0x1fffff | (0x7 << 24)); -+ insn |= (valid24 & 0x1fffff); -+ insn |= ((valid24 & 0xe00000) << 3); -+ *location = insn; -+ } -+ break; -+ case R_UBICOM32_LO7_S: -+ case R_UBICOM32_LO7_2_S: -+ case R_UBICOM32_LO7_4_S: -+ { -+ /* -+ * Bits 0 - 6 of the relocation are encoded into the -+ * 7bit unsigned immediate fields of the SOURCE-1 field -+ * of the instruction. The immediate value is left -+ * shifted by (0, 1, 2) based on the operand size. -+ */ -+ uint32_t valid7 = v & 0x7f; -+ insn = *location; -+ -+ if (elf32_rtype == R_UBICOM32_LO7_2_S) { -+ valid7 >>= 1; -+ } else if (elf32_rtype == R_UBICOM32_LO7_4_S) { -+ valid7 >>= 2; -+ } -+ -+ insn &= ~(0x1f | (0x3 << 8)); -+ insn |= (valid7 & 0x1f); -+ insn |= ((valid7 & 0x60) << 3); -+ *location = insn; -+ } -+ break; -+ case R_UBICOM32_LO7_D: -+ case R_UBICOM32_LO7_2_D: -+ case R_UBICOM32_LO7_4_D: -+ { -+ /* -+ * Bits 0 - 6 of the relocation are encoded into the -+ * 7bit unsigned immediate fields of the DESTINATION -+ * field of the instruction. The immediate value is -+ * left shifted by (0, 1, 2) based on the operand size. -+ */ -+ uint32_t valid7 = v & 0x7f; -+ insn = *location; -+ -+ if (elf32_rtype == R_UBICOM32_LO7_2_D) { -+ valid7 >>= 1; -+ } else if (elf32_rtype == R_UBICOM32_LO7_4_D) { -+ valid7 >>= 2; -+ } -+ -+ insn &= ~((0x1f | (0x3 << 8)) << 16); -+ insn |= ((valid7 & 0x1f) << 16); -+ insn |= ((valid7 & 0x60) << 19); -+ *location = insn; -+ } -+ break; -+ case R_UBICOM32_LO7_CALLI: -+ case R_UBICOM32_LO16_CALLI: -+ { -+ /* -+ * Extract the offset for a CALLI instruction. The -+ * offsets can be either 7 bits or 18 bits. Since all -+ * instructions in ubicom32 architecture are at work -+ * aligned addresses the truncated offset is right -+ * shifted by 2 before being encoded in the instruction. -+ */ -+ uint32_t val; -+ if (elf32_rtype == R_UBICOM32_LO7_CALLI) { -+ val = v & 0x7f; -+ } else { -+ val = v & 0x3ffff; -+ } -+ -+ val >>= 2; -+ -+ insn = *location; -+ -+ insn &= ~0x071f071f; -+ insn |= (val & 0x1f) << 0; -+ val >>= 5; -+ insn |= (val & 0x07) << 8; -+ val >>= 3; -+ insn |= (val & 0x1f) << 16; -+ val >>= 5; -+ insn |= (val & 0x07) << 24; -+ *location = insn; -+ } -+ break; -+ case R_UBICOM32_24_PCREL: -+ { -+ /* -+ * Extract 26 bit signed PC relative offset for CALL -+ * instructions. Since instruction addresses are word -+ * aligned the offset is right shited by 2 before -+ * encoding into instruction. -+ */ -+ int32_t val = v - (int32_t)location; -+ -+ /* -+ * Check that the top 7 bits are all equal to the sign -+ * bit (26), i.e all 0's or all 1's. If they are not then -+ * the absolute difference is greater than 25 bits. -+ */ -+ if (((uint32_t)val & 0xFE000000) != 0xFE000000 && -+ ((uint32_t)val & 0xFE000000) != 0x0) { -+ /* -+ * The relocation is beyond our addressable -+ * range with a 26 bit call. -+ */ -+ printk(KERN_ERR "module %s: PC Relative " -+ "relocation out of range: " -+ "%u (%x->%x, %x)\n", -+ me->name, elf32_rtype, -+ v, (uint32_t) location, val); -+ return -ENOEXEC; -+ } -+ -+ val = (val & 0x3ffffff) >> 2; -+ insn = *location; -+ insn = insn & 0xf8e00000; -+ -+ insn |= (val >> 21) << 24; -+ insn |= (val & 0x1fffff); -+ *location = insn; -+ } -+ break; -+ case R_UBICOM32_LO16: -+ case R_UBICOM32_HI16: -+ { -+ /* -+ * 16 bit immediate value that is encoded into bit 0 - -+ * 15 of the instruction. -+ */ -+ uint32_t val; -+ -+ if (elf32_rtype == R_UBICOM32_LO16) { -+ val = v & 0xffff; -+ } else { -+ val = (v >> 16) & 0xffff; -+ } -+ -+ insn = *location; -+ insn &= 0xffff0000; -+ -+ insn |= val; -+ *location = insn; -+ } -+ break; -+ case R_UBICOM32_21_PCREL: -+ { -+ /* -+ * Extract 23 bit signed PC relative offset for JMP -+ * instructions. Since instruction addresses are word -+ * aligned the offset is right shited by 2 before -+ * encoding into instruction. -+ */ -+ int32_t val = v - (int32_t)location; -+ -+ val = (val & 0x7fffff) >> 2; -+ insn = *location; -+ insn = insn & 0xffe00000; -+ -+ insn |= (val >> 21) << 24; -+ insn |= val; -+ *location = insn; -+ } -+ break; -+ default: -+ BUG(); -+ printk(KERN_ERR "module %s: Unknown relocation: %u\n", -+ me->name, elf32_rtype); -+ return -ENOEXEC; -+ } -+ } -+ return 0; -+} -+ -+int module_finalize(const Elf_Ehdr *hdr, -+ const Elf_Shdr *sechdrs, -+ struct module *mod) -+{ -+ unsigned int i, strindex = 0, symindex = 0; -+ char *secstrings; -+ int err; -+ -+ err = module_bug_finalize(hdr, sechdrs, mod); -+ if (err) -+ return err; -+ -+ if (!mod->arch.ocm_inst) { -+ /* -+ * No OCM code, so nothing more to do. -+ */ -+ return 0; -+ } -+ -+ secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; -+ -+ for (i = 1; i < hdr->e_shnum; i++) { -+ /* Internal symbols and strings. */ -+ if (sechdrs[i].sh_type == SHT_SYMTAB) { -+ symindex = i; -+ strindex = sechdrs[i].sh_link; -+ } -+ } -+ -+ for (i = 1; i < hdr->e_shnum; i++) { -+ const char *strtab = (char *)sechdrs[strindex].sh_addr; -+ unsigned int info = sechdrs[i].sh_info; -+ -+ /* Not a valid relocation section? */ -+ if (info >= hdr->e_shnum) -+ continue; -+ -+ if ((sechdrs[i].sh_type == SHT_RELA) && -+ (strncmp(".rela.ocm_text", -+ secstrings + sechdrs[i].sh_name, 5 + 9) == 0)) { -+ err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab, -+ symindex, i, mod); -+ if (err) -+ return err; -+ } -+ } -+ -+ return 0; -+} -+ -+void module_arch_cleanup(struct module *mod) -+{ -+ module_bug_cleanup(mod); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/os_node.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/os_node.c ---- linux-2.6.30.10/arch/ubicom32/kernel/os_node.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/os_node.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,88 @@ -+/* -+ * arch/ubicom32/kernel/os_node.c -+ * -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ */ -+#include "linux/types.h" -+#include "linux/linkage.h" -+#include "linux/uts.h" -+#include "linux/utsrelease.h" -+#include "linux/version.h" -+#include -+#include -+#include -+ -+extern asmlinkage void *_start; -+ -+/* -+ * This file provides static information to the boot code allowing it to decide -+ * if the os is compatible. Thus hopefully enabling the boot code to prevent -+ * accidentally booting a kernel that has no hope of running. -+ */ -+struct os_node { -+ struct devtree_node node; -+ unsigned long version; /* Always 1 */ -+ unsigned long entry_point; -+ const char os_name[32]; /* For diagnostic purposes only */ -+ const char os_version_str[32]; -+ unsigned long os_version_num; -+ unsigned long expected_ocm_code_start;/* OS Code */ -+ unsigned long expected_ocm_data_end; /* OS Data */ -+ unsigned long expected_ram_start; -+ unsigned long expected_ram_end; -+ unsigned long arch_version; -+ unsigned long expected_os_syscall_begin; -+ unsigned long expected_os_syscall_end; -+}; -+ -+ -+extern void __os_syscall_begin; -+extern void __os_syscall_end; -+/* -+ * The os_node is only referenced by head.S and should never be modified at -+ * run-time. -+ */ -+asmlinkage const struct os_node _os_node = { -+ .node = { -+ .next = NULL, -+ .name = { "OS" }, -+ .magic = 0x10203040, -+ }, -+ .version = 0x10002, -+ .entry_point = (unsigned long)&_start, -+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE -+ .expected_ocm_code_start = OCMSTART + APP_OCM_CODE_SIZE, -+ .expected_ocm_data_end = OCMEND - APP_OCM_DATA_SIZE, -+#else -+ .expected_ocm_code_start = OCMEND, -+ .expected_ocm_data_end = OCMEND, -+#endif -+ .os_name = { UTS_SYSNAME }, -+ .os_version_str = { UTS_RELEASE }, -+ .os_version_num = LINUX_VERSION_CODE, -+ .expected_ram_start = KERNELSTART, -+ .expected_ram_end = SDRAMSTART + CONFIG_MIN_RAMSIZE, -+ .arch_version = UBICOM32_ARCH_VERSION, -+ .expected_os_syscall_begin = (unsigned long)&__os_syscall_begin, -+ .expected_os_syscall_end = (unsigned long)&__os_syscall_end, -+ -+ -+}; -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/process.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/process.c ---- linux-2.6.30.10/arch/ubicom32/kernel/process.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/process.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,634 @@ -+/* -+ * arch/ubicom32/kernel/process.c -+ * Ubicom32 architecture-dependent process handling. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1995 Hamish Macdonald -+ * -+ * 68060 fixes by Jesper Skov -+ * -+ * uClinux changes -+ * Copyright (C) 2000-2002, David McCullough -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+/* -+ * This file handles the architecture-dependent parts of process handling.. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DUMP_RANGE_REGISTER(REG, IDX) asm volatile ( \ -+ " move.4 %0, "REG"_RANGE"IDX"_EN \n\t" \ -+ " move.4 %1, "REG"_RANGE"IDX"_LO \n\t" \ -+ " move.4 %2, "REG"_RANGE"IDX"_HI \n\t" \ -+ : "=d"(en), "=d"(lo), "=d"(hi) \ -+ ); \ -+ printk(KERN_NOTICE REG"Range"IDX": en:%08x, range: %08x-%08x\n", \ -+ (unsigned int)en, \ -+ (unsigned int)lo, \ -+ (unsigned int)hi) -+ -+asmlinkage void ret_from_fork(void); -+ -+void (*pm_power_off)(void) = machine_power_off; -+EXPORT_SYMBOL(pm_power_off); -+ -+/* machine-dependent / hardware-specific power functions */ -+void (*mach_reset)(void); -+void (*mach_halt)(void); -+void (*mach_power_off)(void); -+ -+/* -+ * cpu_idle() -+ * The idle thread. -+ * -+ * Our idle loop suspends and is woken up by a timer interrupt. -+ */ -+void cpu_idle(void) -+{ -+ while (1) { -+ local_irq_disable(); -+ while (!need_resched()) { -+ local_irq_enable(); -+ thread_suspend(); -+ local_irq_disable(); -+ } -+ local_irq_enable(); -+ preempt_enable_no_resched(); -+ schedule(); -+ preempt_disable(); -+ } -+} -+ -+/* -+ * dump_fpu() -+ * -+ * Fill in the fpu structure for a core dump. (just a stub as we don't have -+ * an fpu) -+ */ -+int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs) -+{ -+ return 1; -+} -+ -+/* -+ * machine_restart() -+ * Resets the system. -+ */ -+void machine_restart(char *__unused) -+{ -+ /* -+ * Disable all threads except myself. We can do this -+ * directly without needing to call smp_send_stop -+ * because we have a unique architecture where -+ * one thread can disable one or more other threads. -+ */ -+ thread_disable_others(); -+ -+ /* -+ * Call the hardware-specific machine reset function. -+ */ -+ if (mach_reset) { -+ mach_reset(); -+ } -+ -+ printk(KERN_EMERG "System Restarting\n"); -+ -+ /* -+ * Set watchdog to trigger (after 1ms delay) (12 Mhz is the fixed OSC) -+ */ -+ UBICOM32_IO_TIMER->tkey = TIMER_TKEYVAL; -+ UBICOM32_IO_TIMER->wdcom = UBICOM32_IO_TIMER->mptval + -+ (12000000 / 1000); -+ UBICOM32_IO_TIMER->wdcfg = 0; -+ UBICOM32_IO_TIMER->tkey = 0; -+ -+ /* -+ * Wait for watchdog -+ */ -+ asm volatile ( -+ " move.4 MT_EN, #0 \n\t" -+ " pipe_flush 0 \n\t" -+ ); -+ -+ local_irq_disable(); -+ for (;;) { -+ thread_suspend(); -+ } -+} -+ -+/* -+ * machine_halt() -+ * Halt the machine. -+ * -+ * Similar to machine_power_off, but don't shut off power. Add code -+ * here to freeze the system for e.g. post-mortem debug purpose when -+ * possible. This halt has nothing to do with the idle halt. -+ */ -+void machine_halt(void) -+{ -+ /* -+ * Disable all threads except myself. We can do this -+ * directly without needing to call smp_send_stop -+ * because we have a unique architecture where -+ * one thread can disable one or more other threads. -+ */ -+ thread_disable_others(); -+ -+ /* -+ * Call the hardware-specific machine halt function. -+ */ -+ if (mach_halt) { -+ mach_halt(); -+ } -+ -+ printk(KERN_EMERG "System Halted, OK to turn off power\n"); -+ local_irq_disable(); -+ for (;;) { -+ thread_suspend(); -+ } -+} -+ -+/* -+ * machine_power_off() -+ * Turn the power off, if a power off handler is defined, otherwise, spin -+ * endlessly. -+ */ -+void machine_power_off(void) -+{ -+ /* -+ * Disable all threads except myself. We can do this -+ * directly without needing to call smp_send_stop -+ * because we have a unique architecture where -+ * one thread can disable one or more other threads. -+ */ -+ thread_disable_others(); -+ -+ /* -+ * Call the hardware-specific machine power off function. -+ */ -+ if (mach_power_off) { -+ mach_power_off(); -+ } -+ -+ printk(KERN_EMERG "System Halted, OK to turn off power\n"); -+ local_irq_disable(); -+ for (;;) { -+ thread_suspend(); -+ } -+} -+ -+/* -+ * address_is_valid() -+ * check if an address is valid -- (for read access) -+ */ -+static bool address_is_valid(const void *address) -+{ -+ int addr = (int)address; -+ unsigned long socm, eocm, sdram, edram; -+ -+ if (addr & 3) -+ return false; -+ -+ processor_ocm(&socm, &eocm); -+ processor_dram(&sdram, &edram); -+ if (addr >= socm && addr < eocm) -+ return true; -+ -+ if (addr >= sdram && addr < edram) -+ return true; -+ -+ return false; -+} -+ -+/* -+ * vma_path_name_is_valid() -+ * check if path_name of a vma is a valid string -+ */ -+static bool vma_path_name_is_valid(const char *str) -+{ -+#define MAX_NAME_LEN 256 -+ int i = 0; -+ if (!address_is_valid(str)) -+ return false; -+ -+ for (; i < MAX_NAME_LEN; i++, str++) { -+ if (*str == '\0') -+ return true; -+ } -+ -+ return false; -+} -+ -+/* -+ * show_vmas() -+ * show vma info of a process -+ */ -+void show_vmas(struct task_struct *task) -+{ -+#ifdef CONFIG_DEBUG_VERBOSE -+#define UBICOM32_MAX_VMA_COUNT 1024 -+ -+ struct vm_area_struct *vma; -+ struct file *file; -+ char *name = ""; -+ int flags, loop = 0; -+ -+ printk(KERN_NOTICE "Start of vma list\n"); -+ -+ if (!address_is_valid(task) || !address_is_valid(task->mm)) -+ goto error; -+ -+ vma = task->mm->mmap; -+ while (vma) { -+ if (!address_is_valid(vma)) -+ goto error; -+ -+ flags = vma->vm_flags; -+ file = vma->vm_file; -+ -+ if (file) { -+ /* seems better to use dentry op here, but sanity check is easier this way */ -+ if (!address_is_valid(file) || !address_is_valid(file->f_path.dentry) || !vma_path_name_is_valid(file->f_path.dentry->d_name.name)) -+ goto error; -+ -+ name = (char *)file->f_path.dentry->d_name.name; -+ } -+ -+ /* Similar to /proc/pid/maps format */ -+ printk(KERN_NOTICE "%08lx-%08lx %c%c%c%c %08lx %s\n", -+ vma->vm_start, -+ vma->vm_end, -+ flags & VM_READ ? 'r' : '-', -+ flags & VM_WRITE ? 'w' : '-', -+ flags & VM_EXEC ? 'x' : '-', -+ flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', -+ vma->vm_pgoff << PAGE_SHIFT, -+ name); -+ -+ vma = vma->vm_next; -+ -+ if (loop++ > UBICOM32_MAX_VMA_COUNT) -+ goto error; -+ } -+ -+ printk(KERN_NOTICE "End of vma list\n"); -+ return; -+ -+error: -+ printk(KERN_NOTICE "\nCorrupted vma list, abort!\n"); -+#endif -+} -+ -+/* -+ * show_regs() -+ * Print out all of the registers. -+ */ -+void show_regs(struct pt_regs *regs) -+{ -+ unsigned int i; -+ unsigned int en, lo, hi; -+ -+ printk(KERN_NOTICE "regs: %p, tid: %d\n", -+ (void *)regs, -+ thread_get_self()); -+ -+ printk(KERN_NOTICE "pc: %08x, previous_pc: %08x\n\n", -+ (unsigned int)regs->pc, -+ (unsigned int)regs->previous_pc); -+ -+ printk(KERN_NOTICE "Data registers\n"); -+ for (i = 0; i < 16; i++) { -+ printk("D%02d: %08x, ", i, (unsigned int)regs->dn[i]); -+ if ((i % 4) == 3) { -+ printk("\n"); -+ } -+ } -+ printk("\n"); -+ -+ printk(KERN_NOTICE "Address registers\n"); -+ for (i = 0; i < 8; i++) { -+ printk("A%02d: %08x, ", i, (unsigned int)regs->an[i]); -+ if ((i % 4) == 3) { -+ printk("\n"); -+ } -+ } -+ printk("\n"); -+ -+ printk(KERN_NOTICE "acc0: %08x-%08x, acc1: %08x-%08x\n", -+ (unsigned int)regs->acc0[1], -+ (unsigned int)regs->acc0[0], -+ (unsigned int)regs->acc1[1], -+ (unsigned int)regs->acc1[0]); -+ -+ printk(KERN_NOTICE "mac_rc16: %08x, source3: %08x\n", -+ (unsigned int)regs->mac_rc16, -+ (unsigned int)regs->source3); -+ -+ printk(KERN_NOTICE "inst_cnt: %08x, csr: %08x\n", -+ (unsigned int)regs->inst_cnt, -+ (unsigned int)regs->csr); -+ -+ printk(KERN_NOTICE "int_mask0: %08x, int_mask1: %08x\n", -+ (unsigned int)regs->int_mask0, -+ (unsigned int)regs->int_mask1); -+ -+ /* -+ * Dump range registers -+ */ -+ DUMP_RANGE_REGISTER("I", "0"); -+ DUMP_RANGE_REGISTER("I", "1"); -+ DUMP_RANGE_REGISTER("I", "2"); -+ DUMP_RANGE_REGISTER("I", "3"); -+ DUMP_RANGE_REGISTER("D", "0"); -+ DUMP_RANGE_REGISTER("D", "1"); -+ DUMP_RANGE_REGISTER("D", "2"); -+ DUMP_RANGE_REGISTER("D", "3"); -+ DUMP_RANGE_REGISTER("D", "4"); -+ -+ printk(KERN_NOTICE "frame_type: %d, nesting_level: %d, thread_type %d\n\n", -+ (int)regs->frame_type, -+ (int)regs->nesting_level, -+ (int)regs->thread_type); -+} -+ -+/* -+ * kernel_thread_helper() -+ * On execution d0 will be 0, d1 will be the argument to be passed to the -+ * kernel function. d2 contains the kernel function that needs to get -+ * called. d3 will contain address to do_exit which need to get moved -+ * into a5. On return from fork the child thread d0 will be 0. We call -+ * this dummy function which in turn loads the argument -+ */ -+asmlinkage void kernel_thread_helper(void); -+ -+/* -+ * kernel_thread() -+ * Create a kernel thread -+ */ -+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) -+{ -+ struct pt_regs regs; -+ -+ memset(®s, 0, sizeof(regs)); -+ -+ regs.dn[1] = (unsigned long)arg; -+ regs.dn[2] = (unsigned long)fn; -+ regs.dn[3] = (unsigned long)do_exit; -+ regs.an[5] = (unsigned long)kernel_thread_helper; -+ regs.pc = (unsigned long)kernel_thread_helper; -+ regs.nesting_level = 0; -+ regs.thread_type = KERNEL_THREAD; -+ -+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, -+ 0, ®s, 0, NULL, NULL); -+} -+EXPORT_SYMBOL(kernel_thread); -+ -+/* -+ * flush_thread() -+ * XXX todo -+ */ -+void flush_thread(void) -+{ -+ /* XXX todo */ -+} -+ -+/* -+ * sys_fork() -+ * Not implemented on no-mmu. -+ */ -+asmlinkage int sys_fork(struct pt_regs *regs) -+{ -+ /* fork almost works, enough to trick you into looking elsewhere :-( */ -+ return -EINVAL; -+} -+ -+/* -+ * sys_vfork() -+ * By the time we get here, the non-volatile registers have also been saved -+ * on the stack. We do some ugly pointer stuff here.. (see also copy_thread -+ * which does context copy). -+ */ -+asmlinkage int sys_vfork(struct pt_regs *regs) -+{ -+ unsigned long old_sp = regs->an[7]; -+ unsigned long old_a5 = regs->an[5]; -+ unsigned long old_return_address; -+ long do_fork_return; -+ -+ /* -+ * Read the old retrun address from the stack. -+ */ -+ if (copy_from_user(&old_return_address, -+ (void *)old_sp, sizeof(unsigned long))) { -+ force_sig(SIGSEGV, current); -+ return 0; -+ } -+ -+ /* -+ * Pop the vfork call frame by setting a5 and pc to the old_return -+ * address and incrementing the stack pointer by 4. -+ */ -+ regs->an[5] = old_return_address; -+ regs->pc = old_return_address; -+ regs->an[7] += 4; -+ -+ do_fork_return = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, -+ regs->an[7], regs, 0, NULL, NULL); -+ -+ /* -+ * Now we have to test if the return code is an error. If it is an error -+ * then restore the frame and we will execute error processing in user -+ * space. Other wise the child and the parent will return to the correct -+ * places. -+ */ -+ if ((unsigned long)(do_fork_return) >= (unsigned long)(-125)) { -+ /* -+ * Error case. We need to restore the frame. -+ */ -+ regs->an[5] = old_a5; -+ regs->pc = old_a5; -+ regs->an[7] = old_sp; -+ } -+ -+ return do_fork_return; -+} -+ -+/* -+ * sys_clone() -+ * creates a child thread. -+ */ -+asmlinkage int sys_clone(unsigned long clone_flags, -+ unsigned long newsp, -+ struct pt_regs *regs) -+{ -+ if (!newsp) -+ newsp = regs->an[7]; -+ return do_fork(clone_flags, newsp, regs, 0, -+ NULL, NULL); -+} -+ -+/* -+ * copy_thread() -+ * low level thread copy, only used by do_fork in kernel/fork.c -+ */ -+int copy_thread(unsigned long clone_flags, -+ unsigned long usp, unsigned long topstk, -+ struct task_struct *p, struct pt_regs *regs) -+ -+{ -+ struct pt_regs *childregs; -+ -+ childregs = (struct pt_regs *) -+ (task_stack_page(p) + THREAD_SIZE - 8) - 1; -+ -+ *childregs = *regs; -+ -+ /* -+ * Set return value for child to be 0. -+ */ -+ childregs->dn[0] = 0; -+ -+ if (usp) -+ childregs->an[7] = usp; -+ else -+ childregs->an[7] = (unsigned long)task_stack_page(p) + -+ THREAD_SIZE - 8; -+ -+ /* -+ * Set up the switch_to frame to return to "ret_from_fork" -+ */ -+ p->thread.a5 = (unsigned long)ret_from_fork; -+ p->thread.sp = (unsigned long)childregs; -+ -+ return 0; -+} -+ -+/* -+ * sys_execve() -+ * executes a new program. -+ */ -+asmlinkage int sys_execve(char *name, char **argv, -+ char **envp, struct pt_regs *regs) -+{ -+ int error; -+ char *filename; -+ -+ lock_kernel(); -+ filename = getname(name); -+ error = PTR_ERR(filename); -+ if (IS_ERR(filename)) -+ goto out; -+ error = do_execve(filename, argv, envp, regs); -+ putname(filename); -+ asm (" .global sys_execve_complete\n" -+ " sys_execve_complete:"); -+out: -+ unlock_kernel(); -+ return error; -+} -+ -+/* -+ * Return saved PC of a blocked thread. -+ */ -+unsigned long thread_saved_pc(struct task_struct *tsk) -+{ -+ return tsk->thread.a5; -+} -+ -+ -+unsigned long get_wchan(struct task_struct *p) -+{ -+ unsigned long pc; -+ -+ /* -+ * If we don't have a process, or it is not the current -+ * one or not RUNNING, it makes no sense to ask for a -+ * wchan. -+ */ -+ if (!p || p == current || p->state == TASK_RUNNING) -+ return 0; -+ -+ /* -+ * TODO: If the process is in the middle of schedule, we -+ * are supposed to do something different but for now we -+ * will return the same thing in both situations. -+ */ -+ pc = thread_saved_pc(p); -+ if (in_sched_functions(pc)) -+ return pc; -+ return pc; -+} -+ -+ -+/* -+ * Infrequently used interface to dump task registers to core files. -+ */ -+int dump_task_regs(struct task_struct *task, elf_gregset_t *elfregs) -+{ -+ struct pt_regs *regs = task_pt_regs(task); -+ *(struct pt_regs *)elfregs = *regs; -+ -+ return 1; -+} -+ -+/* -+ * __switch_to is the function that implements the contex save and -+ * switch within the kernel. Since this is a function call very few -+ * registers have to be saved to pull this off. d0 holds prev and we -+ * want to preserve it. prev_switch is a pointer to task->thread -+ * structure. This is where we will save the register state. next_switch -+ * is pointer to the next task's thread structure that holds the -+ * registers. -+ */ -+asmlinkage void *__switch_to(struct task_struct *prev, -+ struct thread_struct *prev_switch, -+ struct thread_struct *next_switch) -+ __attribute__((naked)); -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/processor.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/processor.c ---- linux-2.6.30.10/arch/ubicom32/kernel/processor.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/processor.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,348 @@ -+/* -+ * arch/ubicom32/kernel/processor.c -+ * Ubicom32 architecture processor info implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct procnode { -+ struct devtree_node dn; -+ unsigned int threads; -+ unsigned int timers; -+ unsigned int frequency; -+ unsigned int ddr_frequency; -+ unsigned int interrupt0; -+ unsigned int interrupt1; -+ void *socm; -+ void *eocm; -+ void *sdram; -+ void *edram; -+ unsigned int arch_version; -+ void *os_syscall_begin; -+ void *os_syscall_end; -+}; -+ -+struct procnode *pn; -+ -+/* -+ * show_processorinfo() -+ * Print the actual processor information. -+ */ -+static void show_processorinfo(struct seq_file *m) -+{ -+ char *cpu, *mmu, *fpu; -+ unsigned int clockfreq; -+ unsigned int chipid; -+ -+ cpu = CPU; -+ mmu = "none"; -+ fpu = "none"; -+ -+ asm volatile ( -+ "move.4 %0, CHIP_ID \n\t" -+ : "=r" (chipid) -+ ); -+ -+ /* -+ * General Processor Information. -+ */ -+ seq_printf(m, "Vendor:\t\t%s\n", "Ubicom"); -+ seq_printf(m, "CPU:\t\t%s\n", cpu); -+ seq_printf(m, "MMU:\t\t%s\n", mmu); -+ seq_printf(m, "FPU:\t\t%s\n", fpu); -+ seq_printf(m, "Arch:\t\t%hx\n", chipid >> 16); -+ seq_printf(m, "Rev:\t\t%hx\n", (chipid & 0xffff)); -+ -+ /* -+ * Now compute the clock frequency in Mhz. -+ */ -+ clockfreq = processor_frequency(); -+ seq_printf(m, "Clock Freq:\t%u.0 MHz\n", -+ clockfreq / 1000000); -+ seq_printf(m, "DDR Freq:\t%u.0 MHz\n", -+ pn ? pn->ddr_frequency / 1000000 : 0); -+ seq_printf(m, "BogoMips:\t%lu.%02lu\n", -+ (loops_per_jiffy * HZ) / 500000, -+ ((loops_per_jiffy * HZ) / 5000) % 100); -+ seq_printf(m, "Calibration:\t%lu loops\n", (loops_per_jiffy * HZ)); -+} -+ -+/* -+ * show_cpuinfo() -+ * Get CPU information for use by the procfs. -+ */ -+static int show_cpuinfo(struct seq_file *m, void *v) -+{ -+ unsigned long n = (unsigned long)v - 1; -+ -+#if defined(CONFIG_SMP) -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, n); -+#endif -+ -+ /* -+ * Print the general processor information on the first -+ * call. -+ */ -+ if (n == 0) { -+ show_processorinfo(m); -+ } -+ -+#if defined(CONFIG_SMP) -+ /* -+ * For each hwthread, print if this hwthread is running Linux -+ * or is an I/O thread. -+ */ -+ if (cpu_isset(n, cpu_online_map)) { -+ seq_printf(m, "cpu[%02lu]:\tthread id - %lu\n", n, p->tid); -+ } else { -+ seq_printf(m, "cpu[%02lu]:\toff-line\n", n); -+ } -+#endif -+ return 0; -+ -+} -+ -+static void *c_start(struct seq_file *m, loff_t *pos) -+{ -+ unsigned long i = *pos; -+ -+ return i < NR_CPUS ? (void *)(i + 1) : NULL; -+} -+ -+static void *c_next(struct seq_file *m, void *v, loff_t *pos) -+{ -+ ++*pos; -+ return c_start(m, pos); -+} -+ -+static void c_stop(struct seq_file *m, void *v) -+{ -+} -+ -+const struct seq_operations cpuinfo_op = { -+ .start = c_start, -+ .next = c_next, -+ .stop = c_stop, -+ .show = show_cpuinfo, -+}; -+ -+/* -+ * processor_timers() -+ * Returns the timers available to Linux. -+ */ -+unsigned int processor_timers(void) -+{ -+ if (!pn) { -+ return 0; -+ } -+ return pn->timers; -+} -+ -+/* -+ * processor_threads() -+ * Returns the threads available to Linux. -+ */ -+unsigned int processor_threads(void) -+{ -+ if (!pn) { -+ return 0; -+ } -+ return pn->threads; -+} -+ -+/* -+ * processor_frequency() -+ * Returns the frequency of the system clock. -+ */ -+unsigned int processor_frequency(void) -+{ -+ if (!pn) { -+ return 0; -+ } -+ return pn->frequency; -+} -+EXPORT_SYMBOL(processor_frequency); -+ -+/* -+ * processor_interrupts() -+ * Return the interrupts that are setup at boot time. -+ */ -+int processor_interrupts(unsigned int *int0, unsigned int *int1) -+{ -+ if (!pn) { -+ return -EFAULT; -+ } -+ -+ if (int0) { -+ *int0 = pn->interrupt0; -+ } -+ -+ if (int1) { -+ *int1 = pn->interrupt1; -+ } -+ return 0; -+} -+ -+/* -+ * processor_ocm() -+ * Returns the start and end of OCM available to Linux. -+ */ -+void processor_ocm(unsigned long *socm, unsigned long *eocm) -+{ -+ *socm = (unsigned long)pn->socm; -+ *eocm = (unsigned long)pn->eocm; -+} -+ -+/* -+ * processor_dram() -+ * Returns the start and end of dram available to Linux. -+ */ -+void processor_dram(unsigned long *sdram, unsigned long *edram) -+{ -+ *sdram = (unsigned long)pn->sdram; -+ *edram = (unsigned long)pn->edram; -+} -+ -+/* -+ * processor_validate_failed() -+ * Returns the dram available to Linux. -+ */ -+static noinline void processor_validate_failed(void) -+{ -+ while (1) -+ THREAD_STALL; -+} -+ -+/* -+ * processor_validate() -+ * Validates the procnode against limitations of this link/built. -+ */ -+static void processor_validate(void) -+{ -+ void *dram_start = (void *)(KERNELSTART); -+ void *dram_end = (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE); -+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE -+ void *ocm_code_start = (void *)(OCMSTART + APP_OCM_CODE_SIZE); -+ void *ocm_data_end = (void *)(OCMEND - APP_OCM_DATA_SIZE); -+#endif -+ extern void __os_syscall_begin; -+ extern void __os_syscall_end; -+ int proc_node_valid = 1; -+ -+ if (!pn) { -+ printk(KERN_ERR "ERROR: processor node not found\n"); -+ goto error; -+ } -+ -+ -+ if (dram_start < pn->sdram || dram_end > pn->edram) { -+ printk(KERN_ERR "ERROR: processor dram mismatch %p-%p " -+ "available but we are expecting %p-%p\n", -+ pn->sdram, pn->edram, dram_start, dram_end); -+ proc_node_valid = 0; -+ } else { -+ printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n", -+ pn->sdram, pn->edram, dram_start, dram_end); -+ } -+ if (&__os_syscall_begin < pn->os_syscall_begin || -+ &__os_syscall_end > pn->os_syscall_end) { -+ printk(KERN_ERR "ERROR: processor syscall area mismatch " -+ "%p-%p available but we are expecting %p-%p\n", -+ pn->os_syscall_begin, pn->os_syscall_end, -+ &__os_syscall_begin, &__os_syscall_end); -+ proc_node_valid = 0; -+ } else { -+ printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n", -+ pn->sdram, pn->edram, dram_start, dram_end); -+ } -+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE -+ if (ocm_code_start < pn->socm || ocm_data_end > pn->eocm) { -+ printk(KERN_ERR "ERROR: processor ocm mismatch %p-%p " -+ "available but we are expecting %p-%p\n", -+ pn->socm, pn->eocm, ocm_code_start, ocm_data_end); -+ proc_node_valid = 0; -+ } else { -+ printk(KERN_INFO "processor ocm %p-%p, expecting %p-%p\n", -+ pn->socm, pn->eocm, ocm_code_start, ocm_data_end); -+ -+ } -+#endif -+ -+ if (UBICOM32_ARCH_VERSION != pn->arch_version) { -+ printk(KERN_ERR "ERROR: processor arch mismatch, kernel" -+ "compiled for %d found %d\n", -+ UBICOM32_ARCH_VERSION, pn->arch_version); -+ proc_node_valid = 0; -+ } -+ -+ if (proc_node_valid) -+ return; -+error: -+ processor_validate_failed(); -+} -+ -+void __init processor_init(void) -+{ -+ /* -+ * If we do not have a trap node in the device tree, we leave the fault -+ * handling to the underlying hardware. -+ */ -+ pn = (struct procnode *)devtree_find_node("processor"); -+ -+ processor_validate(); -+ -+ /* -+ * If necessary correct the initial range registers to cover the -+ * complete physical space -+ */ -+ if (pn->edram > (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE)) { -+ printk(KERN_INFO "updating range registers for expanded dram\n"); -+ asm volatile ( -+ " move.4 D_RANGE1_HI, %0 \t\n" -+ " move.4 I_RANGE0_HI, %0 \t\n" -+#ifdef CONFIG_PROTECT_KERNEL -+ " move.4 D_RANGE2_HI, %0 \t\n" -+ " move.4 I_RANGE2_HI, %0 \t\n" -+#endif -+ : : "a"((unsigned long)pn->edram - 4) -+ ); -+ } -+ -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/ptrace.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/ptrace.c ---- linux-2.6.30.10/arch/ubicom32/kernel/ptrace.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/ptrace.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,275 @@ -+/* -+ * arch/ubicom32/kernel/ptrace.c -+ * Ubicom32 architecture ptrace implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * (C) 1994 by Hamish Macdonald -+ * Taken from linux/kernel/ptrace.c and modified for M680x0. -+ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * ptrace_getregs() -+ * -+ * Get all user integer registers. -+ */ -+static inline int ptrace_getregs(struct task_struct *task, void __user *uregs) -+{ -+ struct pt_regs *regs = task_pt_regs(task); -+ return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; -+} -+ -+/* -+ * ptrace_get_reg() -+ * -+ * Get contents of register REGNO in task TASK. -+ */ -+static unsigned long ptrace_get_reg(struct task_struct *task, int regno) -+{ -+ if (regno < sizeof(struct pt_regs)) { -+ struct pt_regs *pt_regs = task_pt_regs(task); -+ return *(unsigned long *)((long) pt_regs + regno); -+ } -+ -+ return -EIO; -+} -+ -+/* -+ * ptrace_put_reg() -+ * Write contents of register REGNO in task TASK. -+ */ -+static int ptrace_put_reg(struct task_struct *task, int regno, -+ unsigned long data) -+{ -+ if (regno <= sizeof(struct pt_regs) && regno != PT_FRAME_TYPE) { -+ struct pt_regs *pt_regs = task_pt_regs(task); -+ *(unsigned long *)((long) pt_regs + regno) = data; -+ return 0; -+ } -+ return -EIO; -+} -+ -+/* -+ * ptrace_disable_single_step() -+ * Disable Single Step -+ */ -+static int ptrace_disable_single_step(struct task_struct *task) -+{ -+ /* -+ * Single Step not yet implemented, so must always be disabled -+ */ -+ return 0; -+} -+ -+/* -+ * ptrace_disable() -+ * Make sure the single step bit is not set. -+ * Called by kernel/ptrace.c when detaching.. -+ */ -+void ptrace_disable(struct task_struct *child) -+{ -+ ptrace_disable_single_step(child); -+} -+ -+/* -+ * arch_ptrace() -+ * architecture specific ptrace routine. -+ */ -+long arch_ptrace(struct task_struct *child, long request, long addr, long data) -+{ -+ int ret; -+ switch (request) { -+ /* when I and D space are separate, these will need to be fixed. */ -+ case PTRACE_PEEKTEXT: /* read word at location addr. */ -+ case PTRACE_PEEKDATA: -+ ret = generic_ptrace_peekdata(child, addr, data); -+ break; -+ -+ /* read the word at location addr in the USER area. */ -+ case PTRACE_PEEKUSR: { -+ unsigned long tmp; -+ -+ ret = -EIO; -+ if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP) -+ || (addr & 3)) -+ break; -+ -+ tmp = 0; /* Default return condition */ -+ -+ ret = -EIO; -+ if (addr < sizeof(struct pt_regs)) { -+ tmp = ptrace_get_reg(child, addr); -+ } else if (addr == PT_TEXT_ADDR) { -+ tmp = child->mm->start_code; -+ } else if (addr == PT_TEXT_END_ADDR) { -+ tmp = child->mm->end_code; -+ } else if (addr == PT_DATA_ADDR) { -+ tmp = child->mm->start_data; -+ } else if (addr == PT_EXEC_FDPIC_LOADMAP) { -+#ifdef CONFIG_BINFMT_ELF_FDPIC -+ tmp = child->mm->context.exec_fdpic_loadmap; -+#endif -+ } else if (addr == PT_INTERP_FDPIC_LOADMAP) { -+#ifdef CONFIG_BINFMT_ELF_FDPIC -+ tmp = child->mm->context.interp_fdpic_loadmap; -+#endif -+ } else { -+ break; -+ } -+ -+ ret = put_user(tmp, (unsigned long *)data); -+ break; -+ } -+ -+ case PTRACE_POKETEXT: /* write the word at location addr. */ -+ case PTRACE_POKEDATA: -+ ret = generic_ptrace_pokedata(child, addr, data); -+ -+ /* -+ * If we just changed some code so we need to -+ * correct the caches -+ */ -+ if (request == PTRACE_POKETEXT && ret == 0) { -+ flush_icache_range(addr, addr + 4); -+ } -+ break; -+ -+ case PTRACE_POKEUSR: /* write the word at location addr -+ * in the USER area */ -+ ret = -EIO; -+ -+ if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3)) -+ break; -+ -+ if (addr < sizeof(struct pt_regs)) { -+ ret = ptrace_put_reg(child, addr, data); -+ } -+ break; -+ -+ case PTRACE_SYSCALL: /* continue and stop at next (return from) -+ * syscall */ -+ case PTRACE_CONT: { /* restart after signal. */ -+ -+ ret = -EIO; -+ if (!valid_signal(data)) -+ break; -+ if (request == PTRACE_SYSCALL) -+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -+ else -+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -+ child->exit_code = data; -+ /* make sure the single step bit is not set. */ -+ ptrace_disable_single_step(child); -+ wake_up_process(child); -+ ret = 0; -+ break; -+ } -+ -+ /* -+ * make the child exit. Best I can do is send it a sigkill. -+ * perhaps it should be put in the status that it wants to exit. -+ */ -+ case PTRACE_KILL: { -+ ret = 0; -+ if (child->exit_state == EXIT_ZOMBIE) /* already dead */ -+ break; -+ child->exit_code = SIGKILL; -+ /* make sure the single step bit is not set. */ -+ ptrace_disable_single_step(child); -+ wake_up_process(child); -+ break; -+ } -+ -+ case PTRACE_DETACH: /* detach a process that was attached. */ -+ ret = ptrace_detach(child, data); -+ break; -+ -+ case PTRACE_GETREGS: /* Get all gp regs from the child. */ -+ ptrace_getregs(child, (unsigned long *)data); -+ ret = 0; -+ break; -+ -+ case PTRACE_SETREGS: { /* Set all gp regs in the child. */ -+ int i; -+ unsigned long tmp; -+ int count = sizeof(struct pt_regs) / sizeof(unsigned long); -+ for (i = 0; i < count; i++) { -+ if (get_user(tmp, (unsigned long *) data)) { -+ ret = -EFAULT; -+ break; -+ } -+ ptrace_put_reg(child, sizeof(unsigned long) * i, tmp); -+ data += sizeof(long); -+ } -+ ret = 0; -+ break; -+ } -+ -+ default: -+ return ptrace_request(child, request, addr, data); -+ break; -+ } -+ return ret; -+} -+/* -+ * syscall_trace -+ * -+ * called by syscall enter/exit when the TIF_SYSCALL_TRACE bit is set. -+ */ -+asmlinkage void syscall_trace(void) -+{ -+ struct task_struct *cur = current; -+ if (!test_thread_flag(TIF_SYSCALL_TRACE)) -+ return; -+ if (!(cur->ptrace & PT_PTRACED)) -+ return; -+ ptrace_notify(SIGTRAP | ((cur->ptrace & PT_TRACESYSGOOD) -+ ? 0x80 : 0)); -+ /* -+ * this isn't the same as continuing with a signal, but it will do -+ * for normal use. strace only continues with a signal if the -+ * stopping signal is not SIGTRAP. -brl -+ */ -+ if (cur->exit_code) { -+ send_sig(cur->exit_code, current, 1); -+ current->exit_code = 0; -+ } -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/semaphore.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/semaphore.c ---- linux-2.6.30.10/arch/ubicom32/kernel/semaphore.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/semaphore.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,159 @@ -+/* -+ * arch/ubicom32/kernel/semaphore.c -+ * Ubicom32 architecture semaphore implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+/* -+ * Generic semaphore code. Buyer beware. Do your own -+ * specific changes in -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#ifndef CONFIG_RMW_INSNS -+spinlock_t semaphore_wake_lock; -+#endif -+ -+/* -+ * Semaphores are implemented using a two-way counter: -+ * The "count" variable is decremented for each process -+ * that tries to sleep, while the "waking" variable is -+ * incremented when the "up()" code goes to wake up waiting -+ * processes. -+ * -+ * Notably, the inline "up()" and "down()" functions can -+ * efficiently test if they need to do any extra work (up -+ * needs to do something only if count was negative before -+ * the increment operation. -+ * -+ * waking_non_zero() (from asm/semaphore.h) must execute -+ * atomically. -+ * -+ * When __up() is called, the count was negative before -+ * incrementing it, and we need to wake up somebody. -+ * -+ * This routine adds one to the count of processes that need to -+ * wake up and exit. ALL waiting processes actually wake up but -+ * only the one that gets to the "waking" field first will gate -+ * through and acquire the semaphore. The others will go back -+ * to sleep. -+ * -+ * Note that these functions are only called when there is -+ * contention on the lock, and as such all this is the -+ * "non-critical" part of the whole semaphore business. The -+ * critical part is the inline stuff in -+ * where we want to avoid any extra jumps and calls. -+ */ -+void __up(struct semaphore *sem) -+{ -+ wake_one_more(sem); -+ wake_up(&sem->wait); -+} -+ -+/* -+ * Perform the "down" function. Return zero for semaphore acquired, -+ * return negative for signalled out of the function. -+ * -+ * If called from __down, the return is ignored and the wait loop is -+ * not interruptible. This means that a task waiting on a semaphore -+ * using "down()" cannot be killed until someone does an "up()" on -+ * the semaphore. -+ * -+ * If called from __down_interruptible, the return value gets checked -+ * upon return. If the return value is negative then the task continues -+ * with the negative value in the return register (it can be tested by -+ * the caller). -+ * -+ * Either form may be used in conjunction with "up()". -+ * -+ */ -+ -+ -+#define DOWN_HEAD(task_state) \ -+ \ -+ \ -+ current->state = (task_state); \ -+ add_wait_queue(&sem->wait, &wait); \ -+ \ -+ /* \ -+ * Ok, we're set up. sem->count is known to be less than zero \ -+ * so we must wait. \ -+ * \ -+ * We can let go the lock for purposes of waiting. \ -+ * We re-acquire it after awaking so as to protect \ -+ * all semaphore operations. \ -+ * \ -+ * If "up()" is called before we call waking_non_zero() then \ -+ * we will catch it right away. If it is called later then \ -+ * we will have to go through a wakeup cycle to catch it. \ -+ * \ -+ * Multiple waiters contend for the semaphore lock to see \ -+ * who gets to gate through and who has to wait some more. \ -+ */ \ -+ for (;;) { -+ -+#define DOWN_TAIL(task_state) \ -+ current->state = (task_state); \ -+ } \ -+ current->state = TASK_RUNNING; \ -+ remove_wait_queue(&sem->wait, &wait); -+ -+void __sched __down(struct semaphore *sem) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ -+ DOWN_HEAD(TASK_UNINTERRUPTIBLE) -+ if (waking_non_zero(sem)) -+ break; -+ schedule(); -+ DOWN_TAIL(TASK_UNINTERRUPTIBLE) -+} -+ -+int __sched __down_interruptible(struct semaphore *sem) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ int ret = 0; -+ -+ DOWN_HEAD(TASK_INTERRUPTIBLE) -+ -+ ret = waking_non_zero_interruptible(sem, current); -+ if (ret) { -+ if (ret == 1) -+ /* ret != 0 only if we get interrupted -arca */ -+ ret = 0; -+ break; -+ } -+ schedule(); -+ DOWN_TAIL(TASK_INTERRUPTIBLE) -+ return ret; -+} -+ -+int __down_trylock(struct semaphore *sem) -+{ -+ return waking_non_zero_trylock(sem); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/setup.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/setup.c ---- linux-2.6.30.10/arch/ubicom32/kernel/setup.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/setup.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,194 @@ -+/* -+ * arch/ubicom32/kernel/setup.c -+ * Ubicom32 architecture-dependent parts of system setup. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1999-2007 Greg Ungerer (gerg@snapgear.com) -+ * Copyright (C) 1998,1999 D. Jeff Dionne -+ * Copyleft ()) 2000 James D. Schettine {james@telos-systems.com} -+ * Copyright (C) 1998 Kenneth Albanowski -+ * Copyright (C) 1995 Hamish Macdonald -+ * Copyright (C) 2000 Lineo Inc. (www.lineo.com) -+ * Copyright (C) 2001 Lineo, Inc. -+ * 68VZ328 Fixes/support Evan Stawnyczy -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+unsigned long memory_start; -+EXPORT_SYMBOL(memory_start); -+ -+unsigned long memory_end; -+EXPORT_SYMBOL(memory_end); -+ -+static char __initdata command_line[COMMAND_LINE_SIZE]; -+#ifdef CONFIG_CMDLINE_BOOL -+static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; -+#endif -+ -+extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; -+ -+/* -+ * setup_arch() -+ * Setup the architecture dependent portions of the system. -+ */ -+void __init setup_arch(char **cmdline_p) -+{ -+ int bootmap_size; -+ unsigned long ram_start; -+ -+ processor_init(); -+ bootargs_init(); -+ -+ /* -+ * Use the link for memory_start from the link and the processor -+ * node for memory_end. -+ */ -+ memory_start = PAGE_ALIGN(((unsigned long)&_end)); -+ processor_dram(&ram_start, &memory_end); -+ -+ init_mm.start_code = (unsigned long) &_stext; -+ init_mm.end_code = (unsigned long) &_etext; -+ init_mm.end_data = (unsigned long) &_edata; -+ init_mm.brk = (unsigned long) 0; -+ -+ /* -+ * bootexec copies the original default command line to end of memory. -+ * u-boot can modify it there (i.e. to enable network boot) and the -+ * kernel picks up the modified version. -+ * -+ * mainexec creates a `new default' command_line which is in the -+ * bootargs devnode. It is updated on every firmware update but -+ * not used at the moment. -+ */ -+ strlcpy(boot_command_line, (char *)(memory_end - COMMAND_LINE_SIZE), COMMAND_LINE_SIZE); -+ -+#ifdef CONFIG_CMDLINE_BOOL -+#ifdef CONFIG_CMDLINE_OVERRIDE -+ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); -+#else -+ if (builtin_cmdline[0]) { -+ /* append boot loader cmdline to builtin */ -+ strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE); -+ strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE); -+ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); -+ } -+#endif -+#endif -+ -+ strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); -+ *cmdline_p = command_line; -+ -+ parse_early_param(); -+ -+ printk(KERN_INFO "%s Processor, Ubicom, Inc. \n", CPU); -+ -+#if defined(DEBUG) -+ printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x " -+ "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext, -+ (int) &_sdata, (int) &_edata, -+ (int) &_sbss, (int) &_ebss); -+ printk(KERN_DEBUG "MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ", -+ (int) &_ebss, (int) memory_start, -+ (int) memory_start, (int) memory_end); -+#endif -+ -+#ifdef DEBUG -+ if (strlen(*cmdline_p)) -+ printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p); -+#endif -+ -+#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE) -+ conswitchp = &dummy_con; -+#endif -+ -+ /* -+ * If we have a device tree, see if we have the nodes we need. -+ */ -+ if (devtree) { -+ devtree_print(); -+ } -+ -+ /* -+ * From the arm initialization comment: -+ * -+ * This doesn't seem to be used by the Linux memory manager any -+ * more, but is used by ll_rw_block. If we can get rid of it, we -+ * also get rid of some of the stuff above as well. -+ * -+ * Note: max_low_pfn and max_pfn reflect the number of _pages_ in -+ * the system, not the maximum PFN. -+ */ -+ max_pfn = max_low_pfn = (memory_end - PAGE_OFFSET) >> PAGE_SHIFT; -+ -+ /* -+ * Give all the memory to the bootmap allocator, tell it to put the -+ * boot mem_map at the start of memory. -+ */ -+ bootmap_size = init_bootmem_node( -+ NODE_DATA(0), -+ memory_start >> PAGE_SHIFT, /* map goes here */ -+ PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */ -+ memory_end >> PAGE_SHIFT); -+ /* -+ * Free the usable memory, we have to make sure we do not free -+ * the bootmem bitmap so we then reserve it after freeing it :-) -+ */ -+ free_bootmem(memory_start, memory_end - memory_start); -+ reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT); -+ -+ /* -+ * Get kmalloc into gear. -+ */ -+ paging_init(); -+ -+ /* -+ * Fix up the thread_info structure, indicate this is a mainline Linux -+ * thread and setup the sw_ksp(). -+ */ -+ sw_ksp[thread_get_self()] = (unsigned int) current_thread_info(); -+ thread_set_mainline(thread_get_self()); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/signal.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/signal.c ---- linux-2.6.30.10/arch/ubicom32/kernel/signal.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/signal.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,458 @@ -+/* -+ * arch/ubicom32/kernel/signal.c -+ * Ubicom32 architecture signal handling implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1991, 1992 Linus Torvalds -+ * Linux/m68k support by Hamish Macdonald -+ * 68060 fixes by Jesper Skov -+ * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab -+ * mathemu support by Roman Zippel -+ * ++roman (07/09/96): implemented signal stacks -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * -+ * mathemu support by Roman Zippel -+ * (Note: fpstate in the signal context is completely ignored for the emulator -+ * and the internal floating point format is put on stack) -+ * -+ * ++roman (07/09/96): implemented signal stacks (specially for tosemu on -+ * Atari :-) Current limitation: Only one sigstack can be active at one time. -+ * If a second signal with SA_ONSTACK set arrives while working on a sigstack, -+ * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested -+ * signal handlers! -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -+ -+/* -+ * asm signal return handlers. -+ */ -+void ret_from_user_signal(void); -+void ret_from_user_rt_signal(void); -+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); -+ -+/* -+ * Common signal suspend implementation -+ */ -+static int signal_suspend(sigset_t *saveset, struct pt_regs *regs) -+{ -+ regs->dn[0] = -EINTR; -+ while (1) { -+ current->state = TASK_INTERRUPTIBLE; -+ schedule(); -+ if (!do_signal(saveset, regs)) { -+ continue; -+ } -+ /* -+ * If the current frame type is a signal trampoline we are -+ * actually going to call the signal handler so we return the -+ * desired d0 as the return value. -+ */ -+ if (regs->frame_type == UBICOM32_FRAME_TYPE_SIGTRAMP) { -+ return regs->dn[0]; -+ } -+ return -EINTR; -+ } -+ /* -+ * Should never get here -+ */ -+ BUG(); -+ return 0; -+} -+ -+/* -+ * Atomically swap in the new signal mask, and wait for a signal. -+ */ -+asmlinkage int do_sigsuspend(struct pt_regs *regs) -+{ -+ old_sigset_t mask = regs->dn[0]; -+ sigset_t saveset; -+ -+ mask &= _BLOCKABLE; -+ spin_lock_irq(¤t->sighand->siglock); -+ saveset = current->blocked; -+ siginitset(¤t->blocked, mask); -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->sighand->siglock); -+ -+ /* -+ * Call common handler -+ */ -+ return signal_suspend(&saveset, regs); -+} -+ -+asmlinkage int -+do_rt_sigsuspend(struct pt_regs *regs) -+{ -+ sigset_t *unewset = (sigset_t *)regs->dn[0]; -+ size_t sigsetsize = (size_t)regs->dn[1]; -+ sigset_t saveset, newset; -+ -+ /* XXX: Don't preclude handling different sized sigset_t's. */ -+ if (sigsetsize != sizeof(sigset_t)) -+ return -EINVAL; -+ -+ if (copy_from_user(&newset, unewset, sizeof(newset))) -+ return -EFAULT; -+ sigdelsetmask(&newset, ~_BLOCKABLE); -+ -+ spin_lock_irq(¤t->sighand->siglock); -+ saveset = current->blocked; -+ current->blocked = newset; -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->sighand->siglock); -+ -+ /* -+ * Call common handler -+ */ -+ return signal_suspend(&saveset, regs); -+} -+ -+asmlinkage int -+sys_sigaction(int sig, const struct old_sigaction *act, -+ struct old_sigaction *oact) -+{ -+ struct k_sigaction new_ka, old_ka; -+ int ret; -+ -+ if (act) { -+ old_sigset_t mask; -+ if (!access_ok(VERIFY_READ, act, sizeof(*act)) || -+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) || -+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) -+ return -EFAULT; -+ __get_user(new_ka.sa.sa_flags, &act->sa_flags); -+ __get_user(mask, &act->sa_mask); -+ siginitset(&new_ka.sa.sa_mask, mask); -+ } -+ -+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); -+ -+ if (!ret && oact) { -+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || -+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || -+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) -+ return -EFAULT; -+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags); -+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); -+ } -+ -+ return ret; -+} -+ -+asmlinkage int -+do_sys_sigaltstack(struct pt_regs *regs) -+{ -+ const stack_t *uss = (stack_t *) regs->dn[0]; -+ stack_t *uoss = (stack_t *)regs->dn[1]; -+ return do_sigaltstack(uss, uoss, regs->an[7]); -+} -+ -+/* -+ * fdpic_func_descriptor describes sa_handler when the application is FDPIC -+ */ -+struct fdpic_func_descriptor { -+ unsigned long text; -+ unsigned long GOT; -+}; -+ -+/* -+ * rt_sigframe is stored on the user stack immediately before (above) -+ * the signal handlers stack. -+ */ -+struct rt_sigframe -+{ -+ unsigned long syscall_number; /* This holds __NR_rt_sigreturn. */ -+ unsigned long restore_all_regs; /* This field gets set to 1 if the frame -+ * type is TRAP or INTERRUPT. */ -+ siginfo_t *info; -+ struct ucontext uc; -+ int sig; -+ void *pretcode; -+}; -+ -+/* -+ * Do a signal return; undo the signal stack. -+ */ -+asmlinkage int do_sigreturn(unsigned long __unused) -+{ -+ BUG(); -+ return 0; -+} -+ -+asmlinkage int do_rt_sigreturn(struct pt_regs *regs) -+{ -+ unsigned long usp = regs->an[7]; -+ struct rt_sigframe *frame = (struct rt_sigframe *)(usp); -+ sigset_t set; -+ -+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) -+ goto badframe; -+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) -+ goto badframe; -+ -+ sigdelsetmask(&set, ~_BLOCKABLE); -+ spin_lock_irq(¤t->sighand->siglock); -+ current->blocked = set; -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->sighand->siglock); -+ -+ if (copy_from_user(regs, &frame->uc.uc_mcontext, sizeof(struct pt_regs))) -+ goto badframe; -+ return regs->dn[0]; -+ -+badframe: -+ force_sig(SIGSEGV, current); -+ return 0; -+} -+ -+static inline void * -+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) -+{ -+ unsigned long usp; -+ -+ /* Default to using normal stack. */ -+ usp = regs->an[7]; -+ -+ /* This is the X/Open sanctioned signal stack switching. */ -+ if (ka->sa.sa_flags & SA_ONSTACK) { -+ if (!sas_ss_flags(usp)) -+ usp = current->sas_ss_sp + current->sas_ss_size; -+ } -+ return (void *)((usp - frame_size) & ~0x3); -+} -+ -+/* -+ * signal_trampoline: Defined in ubicom32_syscall.S -+ */ -+asmlinkage void signal_trampoline(void)__attribute__((naked)); -+ -+static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, -+ sigset_t *set, struct pt_regs *regs) -+{ -+ struct rt_sigframe *frame; -+ int err = 0; -+ -+ frame = (struct rt_sigframe *) get_sigframe(ka, regs, sizeof(*frame)); -+ -+ /* -+ * The 'err |=' have been may criticized as bad code style, but I -+ * strongly suspect that we want this code to be fast. So for -+ * now it stays as is. -+ */ -+ err |= __put_user( ( (current_thread_info()->exec_domain) -+ && (current_thread_info()->exec_domain->signal_invmap) -+ && (sig < 32) ) -+ ? current_thread_info()->exec_domain->signal_invmap[sig] -+ : sig, &frame->sig); -+ err |= __put_user(info, &frame->info); -+ -+ /* Create the ucontext. */ -+ err |= __put_user(0, &frame->uc.uc_flags); -+ err |= __put_user(0, &frame->uc.uc_link); -+ err |= __put_user((void *)current->sas_ss_sp, -+ &frame->uc.uc_stack.ss_sp); -+ err |= __put_user(sas_ss_flags(regs->an[7]), -+ &frame->uc.uc_stack.ss_flags); -+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); -+ err |= __put_user(__NR_rt_sigreturn, &frame->syscall_number); -+ if ((regs->frame_type == UBICOM32_FRAME_TYPE_TRAP) || -+ (regs->frame_type == UBICOM32_FRAME_TYPE_INTERRUPT)) { -+ err |= __put_user(1, &frame->restore_all_regs); -+ } else { -+ err |= __put_user(0, &frame->restore_all_regs); -+ } -+ err |= copy_to_user (&frame->uc.uc_mcontext.sc_regs, regs, sizeof(struct pt_regs)); -+ err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); -+ -+ if (err) -+ goto give_sigsegv; -+ -+ /* -+ * Set up registers for signal handler NOTE: Do not modify dn[14], it -+ * contains the userspace tls pointer, so it important that it carries -+ * over to the signal handler. -+ */ -+ regs->an[7] = (unsigned long)frame; -+ regs->pc = (unsigned long) signal_trampoline; -+ regs->an[5] = (unsigned long) signal_trampoline; -+ regs->dn[0] = sig; -+ regs->dn[1] = (unsigned long) frame->info; -+ regs->dn[2] = (unsigned int) &frame->uc; -+ -+ /* -+ * If this is FDPIC then the signal handler is actually a function -+ * descriptor. -+ */ -+ if (current->personality & FDPIC_FUNCPTRS) { -+ struct fdpic_func_descriptor __user *funcptr = -+ (struct fdpic_func_descriptor *) ka->sa.sa_handler; -+ err |= __get_user(regs->dn[3], &funcptr->text); -+ err |= __get_user(regs->an[0], &funcptr->GOT); -+ if (err) -+ goto give_sigsegv; -+ -+ /* -+ * The funcdesc must be in a3 as this is required for the lazy -+ * resolver in ld.so, if the application is not FDPIC a3 is not -+ * used. -+ */ -+ regs->an[3] = (unsigned long) funcptr; -+ -+ } else { -+ regs->dn[3] = (unsigned long)ka->sa.sa_handler; -+ regs->an[0] = 0; -+ } -+ -+ regs->frame_type = UBICOM32_FRAME_TYPE_SIGTRAMP; -+ -+ return; -+ -+give_sigsegv: -+ /* user space exception */ -+ force_sigsegv(sig, current); -+} -+ -+static inline void -+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) -+{ -+ switch (regs->dn[0]) { -+ case -ERESTARTNOHAND: -+ if (!has_handler) -+ goto do_restart; -+ regs->dn[0] = -EINTR; -+ break; -+ -+ case -ERESTARTSYS: -+ if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { -+ regs->dn[0] = -EINTR; -+ break; -+ } -+ /* fallthrough */ -+ case -ERESTARTNOINTR: -+ do_restart: -+ regs->dn[0] = regs->original_dn_0; -+ regs->pc -= 8; -+ regs->an[5] -= 8; -+ break; -+ } -+} -+ -+/* -+ * OK, we're invoking a handler -+ */ -+static void -+handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, -+ sigset_t *oldset, struct pt_regs *regs) -+{ -+ /* are we from a system call? */ -+ if (regs->frame_type == -1) -+ /* If so, check system call restarting.. */ -+ handle_restart(regs, ka, 1); -+ -+ /* set up the stack frame */ -+ setup_rt_frame(sig, ka, info, oldset, regs); -+ -+ if (ka->sa.sa_flags & SA_ONESHOT) -+ ka->sa.sa_handler = SIG_DFL; -+ -+ spin_lock_irq(¤t->sighand->siglock); -+ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); -+ if (!(ka->sa.sa_flags & SA_NODEFER)) -+ sigaddset(¤t->blocked,sig); -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->sighand->siglock); -+} -+ -+/* -+ * Note that 'init' is a special process: it doesn't get signals it doesn't -+ * want to handle. Thus you cannot kill init even with a SIGKILL even by -+ * mistake. -+ */ -+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) -+{ -+ struct k_sigaction ka; -+ siginfo_t info; -+ int signr; -+ -+ /* -+ * We want the common case to go fast, which -+ * is why we may in certain cases get here from -+ * kernel mode. Just return without doing anything -+ * if so. -+ */ -+ if (!user_mode(regs)) -+ return 1; -+ -+ if (!oldset) -+ oldset = ¤t->blocked; -+ -+ signr = get_signal_to_deliver(&info, &ka, regs, NULL); -+ if (signr > 0) { -+ /* Whee! Actually deliver the signal. */ -+ handle_signal(signr, &ka, &info, oldset, regs); -+ return 1; -+ } -+ -+ /* Did we come from a system call? */ -+ if (regs->frame_type == -1) { -+ /* Restart the system call - no handlers present */ -+ handle_restart(regs, NULL, 0); -+ } -+ -+ return 0; -+} -+ -+/* -+ * sys_sigreturn() -+ * Return handler for signal clean-up. -+ * -+ * NOTE: Ubicom32 does not use this syscall. Instead we rely -+ * on do_rt_sigreturn(). -+ */ -+asmlinkage long sys_sigreturn(void) -+{ -+ return -ENOSYS; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/smp.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/smp.c ---- linux-2.6.30.10/arch/ubicom32/kernel/smp.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/smp.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,806 @@ -+/* -+ * arch/ubicom32/kernel/smp.c -+ * SMP implementation for Ubicom32 processors. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1999 Walt Drummond -+ * Copyright (C) 1999 David Mosberger-Tang -+ * Copyright (C) 2001,2004 Grant Grundler -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * Mask the debug printout for IPI because they are too verbose -+ * for regular debugging. -+ */ -+ -+// #define DEBUG_SMP 1 -+#if !defined(DEBUG_SMP) -+#define smp_debug(lvl, ...) -+#else -+static unsigned int smp_debug_lvl = 50; -+#define smp_debug(lvl, printargs...) \ -+ if (lvl >= smp_debug_lvl) { \ -+ printk(printargs); \ -+ } -+#endif -+ -+#if !defined(DEBUG_SMP) -+#define DEBUG_ASSERT(cond) -+#else -+#define DEBUG_ASSERT(cond) \ -+ if (!(cond)) { \ -+ THREAD_STALL; \ -+ } -+#endif -+ -+/* -+ * List of IPI Commands (more than one can be set at a time). -+ */ -+enum ipi_message_type { -+ IPI_NOP, -+ IPI_RESCHEDULE, -+ IPI_CALL_FUNC, -+ IPI_CALL_FUNC_SINGLE, -+ IPI_CPU_STOP, -+ IPI_CPU_TIMER, -+}; -+ -+/* -+ * We maintain a hardware thread oriented view of online threads -+ * and those involved or needing IPI. -+ */ -+static volatile unsigned long smp_online_threads = 0; -+static volatile unsigned long smp_needs_ipi = 0; -+static volatile unsigned long smp_inside_ipi = 0; -+static unsigned long smp_irq_affinity[NR_IRQS]; -+ -+/* -+ * What do we need to track on a per cpu/thread basis? -+ */ -+DEFINE_PER_CPU(struct cpuinfo_ubicom32, cpu_data); -+ -+/* -+ * Each thread cpuinfo IPI information is guarded by a lock -+ * that is kept local to this file. -+ */ -+DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED; -+ -+/* -+ * The IPI(s) are based on a software IRQ through the LDSR. -+ */ -+unsigned int smp_ipi_irq; -+ -+/* -+ * Define a spinlock so that only one cpu is able to modify the -+ * smp_needs_ipi and to set/clear the IRQ at a time. -+ */ -+DEFINE_SPINLOCK(smp_ipi_lock); -+ -+/* -+ * smp_halt_processor() -+ * Halt this hardware thread. -+ */ -+static void smp_halt_processor(void) -+{ -+ int cpuid = thread_get_self(); -+ cpu_clear(smp_processor_id(), cpu_online_map); -+ local_irq_disable(); -+ printk(KERN_EMERG "cpu[%d] has halted. It is not OK to turn off power \ -+ until all cpu's are off.\n", cpuid); -+ for (;;) { -+ thread_suspend(); -+ } -+} -+ -+/* -+ * ipi_interrupt() -+ * Handle an Interprocessor Interrupt. -+ */ -+static irqreturn_t ipi_interrupt(int irq, void *dev_id) -+{ -+ int cpuid = smp_processor_id(); -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid); -+ unsigned long ops; -+ -+ /* -+ * Count this now; we may make a call that never returns. -+ */ -+ p->ipi_count++; -+ -+ /* -+ * We are about to process all ops. If another cpu has stated -+ * that we need an IPI, we will have already processed it. By -+ * clearing our smp_needs_ipi, and processing all ops, -+ * we reduce the number of IPI interrupts. However, this introduces -+ * the possibility that smp_needs_ipi will be clear and the soft irq -+ * will have gone off; so we need to make the get_affinity() path -+ * tolerant of spurious interrupts. -+ */ -+ spin_lock(&smp_ipi_lock); -+ smp_needs_ipi &= ~(1 << p->tid); -+ spin_unlock(&smp_ipi_lock); -+ -+ for (;;) { -+ /* -+ * Read the set of IPI commands we should handle. -+ */ -+ spinlock_t *lock = &per_cpu(ipi_lock, cpuid); -+ spin_lock(lock); -+ ops = p->ipi_pending; -+ p->ipi_pending = 0; -+ spin_unlock(lock); -+ -+ /* -+ * If we have no IPI commands to execute, break out. -+ */ -+ if (!ops) { -+ break; -+ } -+ -+ /* -+ * Execute the set of commands in the ops word, one command -+ * at a time in no particular order. Strip of each command -+ * as we execute it. -+ */ -+ while (ops) { -+ unsigned long which = ffz(~ops); -+ ops &= ~(1 << which); -+ -+ BUG_ON(!irqs_disabled()); -+ switch (which) { -+ case IPI_NOP: -+ smp_debug(100, KERN_INFO "cpu[%d]: " -+ "IPI_NOP\n", cpuid); -+ break; -+ -+ case IPI_RESCHEDULE: -+ /* -+ * Reschedule callback. Everything to be -+ * done is done by the interrupt return path. -+ */ -+ smp_debug(200, KERN_INFO "cpu[%d]: " -+ "IPI_RESCHEDULE\n", cpuid); -+ break; -+ -+ case IPI_CALL_FUNC: -+ smp_debug(100, KERN_INFO "cpu[%d]: " -+ "IPI_CALL_FUNC\n", cpuid); -+ generic_smp_call_function_interrupt(); -+ break; -+ -+ case IPI_CALL_FUNC_SINGLE: -+ smp_debug(100, KERN_INFO "cpu[%d]: " -+ "IPI_CALL_FUNC_SINGLE\n", cpuid); -+ generic_smp_call_function_single_interrupt(); -+ break; -+ -+ case IPI_CPU_STOP: -+ smp_debug(100, KERN_INFO "cpu[%d]: " -+ "IPI_CPU_STOP\n", cpuid); -+ smp_halt_processor(); -+ break; -+ -+#if !defined(CONFIG_LOCAL_TIMERS) -+ case IPI_CPU_TIMER: -+ smp_debug(100, KERN_INFO "cpu[%d]: " -+ "IPI_CPU_TIMER\n", cpuid); -+#if defined(CONFIG_GENERIC_CLOCKEVENTS) -+ local_timer_interrupt(); -+#else -+ update_process_times(user_mode(get_irq_regs())); -+ profile_tick(CPU_PROFILING); -+#endif -+#endif -+ break; -+ -+ default: -+ printk(KERN_CRIT "cpu[%d]: " -+ "Unknown IPI: %lu\n", cpuid, which); -+ -+ return IRQ_NONE; -+ } -+ -+ /* -+ * Let in any pending interrupts -+ */ -+ BUG_ON(!irqs_disabled()); -+ local_irq_enable(); -+ local_irq_disable(); -+ } -+ } -+ return IRQ_HANDLED; -+} -+ -+/* -+ * ipi_send() -+ * Send an Interprocessor Interrupt. -+ */ -+static void ipi_send(int cpu, enum ipi_message_type op) -+{ -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu); -+ spinlock_t *lock = &per_cpu(ipi_lock, cpu); -+ unsigned long flags; -+ -+ /* -+ * We protect the setting of the ipi_pending field and ensure -+ * that the ipi delivery mechanism and interrupt are atomically -+ * handled. -+ */ -+ spin_lock_irqsave(lock, flags); -+ p->ipi_pending |= 1 << op; -+ spin_unlock_irqrestore(lock, flags); -+ -+ spin_lock_irqsave(&smp_ipi_lock, flags); -+ smp_needs_ipi |= (1 << p->tid); -+ ubicom32_set_interrupt(smp_ipi_irq); -+ spin_unlock_irqrestore(&smp_ipi_lock, flags); -+ smp_debug(100, KERN_INFO "cpu[%d]: send: %d\n", cpu, op); -+} -+ -+/* -+ * ipi_send_mask -+ * Send an IPI to each cpu in mask. -+ */ -+static inline void ipi_send_mask(unsigned int op, const struct cpumask mask) -+{ -+ int cpu; -+ for_each_cpu_mask(cpu, mask) { -+ ipi_send(cpu, op); -+ } -+} -+ -+/* -+ * ipi_send_allbutself() -+ * Send an IPI to all threads but ourselves. -+ */ -+static inline void ipi_send_allbutself(unsigned int op) -+{ -+ int self = smp_processor_id(); -+ struct cpumask result; -+ cpumask_copy(&result, &cpu_online_map); -+ cpu_clear(self, result); -+ ipi_send_mask(op, result); -+} -+ -+/* -+ * smp_enable_vector() -+ */ -+static void smp_enable_vector(unsigned int irq) -+{ -+ ubicom32_clear_interrupt(smp_ipi_irq); -+ ldsr_enable_vector(irq); -+} -+ -+/* -+ * smp_disable_vector() -+ * Disable the interrupt by clearing the appropriate bit in the -+ * LDSR Mask Register. -+ */ -+static void smp_disable_vector(unsigned int irq) -+{ -+ ldsr_disable_vector(irq); -+} -+ -+/* -+ * smp_mask_vector() -+ */ -+static void smp_mask_vector(unsigned int irq) -+{ -+ ldsr_mask_vector(irq); -+} -+ -+/* -+ * smp_unmask_vector() -+ */ -+static void smp_unmask_vector(unsigned int irq) -+{ -+ ldsr_unmask_vector(irq); -+} -+ -+/* -+ * smp_end_vector() -+ * Called once an interrupt is completed (reset the LDSR mask). -+ */ -+static void smp_end_vector(unsigned int irq) -+{ -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, smp_processor_id()); -+ spin_lock(&smp_ipi_lock); -+ smp_inside_ipi &= ~(1 << p->tid); -+ if (smp_inside_ipi) { -+ spin_unlock(&smp_ipi_lock); -+ return; -+ } -+ spin_unlock(&smp_ipi_lock); -+ ldsr_unmask_vector(irq); -+ smp_debug(100, KERN_INFO "cpu[%d]: unamesk vector\n", smp_processor_id()); -+} -+ -+/* -+ * Special hanlder functions for SMP. -+ */ -+static struct irq_chip ubicom32_smp_chip = { -+ .name = "UbicoIPI", -+ .startup = NULL, -+ .shutdown = NULL, -+ .enable = smp_enable_vector, -+ .disable = smp_disable_vector, -+ .ack = NULL, -+ .mask = smp_mask_vector, -+ .unmask = smp_unmask_vector, -+ .end = smp_end_vector, -+}; -+ -+/* -+ * smp_reset_ipi() -+ * None of these cpu(s) got their IPI, turn it back on. -+ * -+ * Note: This is called by the LDSR which is not a full -+ * Linux cpu. Thus you must use the raw form of locks -+ * because lock debugging will not work on the partial -+ * cpu nature of the LDSR. -+ */ -+void smp_reset_ipi(unsigned long mask) -+{ -+ __raw_spin_lock(&smp_ipi_lock.raw_lock); -+ smp_needs_ipi |= mask; -+ smp_inside_ipi &= ~mask; -+ ubicom32_set_interrupt(smp_ipi_irq); -+ __raw_spin_unlock(&smp_ipi_lock.raw_lock); -+ smp_debug(100, KERN_INFO "smp: reset IPIs for: 0x%x\n", mask); -+} -+ -+/* -+ * smp_get_affinity() -+ * Choose the thread affinity for this interrupt. -+ * -+ * Note: This is called by the LDSR which is not a full -+ * Linux cpu. Thus you must use the raw form of locks -+ * because lock debugging will not work on the partial -+ * cpu nature of the LDSR. -+ */ -+unsigned long smp_get_affinity(unsigned int irq, int *all) -+{ -+ unsigned long mask = 0; -+ -+ /* -+ * Most IRQ(s) are delivered in a round robin fashion. -+ */ -+ if (irq != smp_ipi_irq) { -+ unsigned long result = smp_irq_affinity[irq] & smp_online_threads; -+ DEBUG_ASSERT(result); -+ *all = 0; -+ return result; -+ } -+ -+ /* -+ * This is an IPI request. Return all cpu(s) scheduled for an IPI. -+ * We also track those cpu(s) that are going to be "receiving" IPI this -+ * round. When all CPU(s) have called smp_end_vector(), -+ * we will unmask the IPI interrupt. -+ */ -+ __raw_spin_lock(&smp_ipi_lock.raw_lock); -+ ubicom32_clear_interrupt(smp_ipi_irq); -+ if (smp_needs_ipi) { -+ mask = smp_needs_ipi; -+ smp_inside_ipi |= smp_needs_ipi; -+ smp_needs_ipi = 0; -+ } -+ __raw_spin_unlock(&smp_ipi_lock.raw_lock); -+ *all = 1; -+ return mask; -+} -+ -+/* -+ * smp_set_affinity() -+ * Set the affinity for this irq but store the value in tid(s). -+ */ -+void smp_set_affinity(unsigned int irq, const struct cpumask *dest) -+{ -+ int cpuid; -+ unsigned long *paffinity = &smp_irq_affinity[irq]; -+ -+ /* -+ * If none specified, all cpus are allowed. -+ */ -+ if (cpus_empty(*dest)) { -+ *paffinity = 0xffffffff; -+ return; -+ } -+ -+ /* -+ * Make sure to clear the old value before setting up the -+ * list. -+ */ -+ *paffinity = 0; -+ for_each_cpu_mask(cpuid, *dest) { -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid); -+ *paffinity |= (1 << p->tid); -+ } -+} -+ -+/* -+ * smp_send_stop() -+ * Send a stop request to all CPU but this one. -+ */ -+void smp_send_stop(void) -+{ -+ ipi_send_allbutself(IPI_CPU_STOP); -+} -+ -+/* -+ * smp_send_timer_all() -+ * Send all cpu(s) but this one, a request to update times. -+ */ -+void smp_send_timer_all(void) -+{ -+ ipi_send_allbutself(IPI_CPU_TIMER); -+} -+ -+/* -+ * smp_timer_broadcast() -+ * Use an IPI to broadcast a timer message -+ */ -+void smp_timer_broadcast(const struct cpumask *mask) -+{ -+ ipi_send_mask(IPI_CPU_TIMER, *mask); -+} -+ -+/* -+ * smp_send_reschedule() -+ * Send a reschedule request to the specified cpu. -+ */ -+void smp_send_reschedule(int cpu) -+{ -+ ipi_send(cpu, IPI_RESCHEDULE); -+} -+ -+/* -+ * arch_send_call_function_ipi() -+ * Cause each cpu in the mask to call the generic function handler. -+ */ -+void arch_send_call_function_ipi_mask(const struct cpumask *mask) -+{ -+ int cpu; -+ for_each_cpu_mask(cpu, *mask) { -+ ipi_send(cpu, IPI_CALL_FUNC); -+ } -+} -+ -+/* -+ * arch_send_call_function_single_ipi() -+ * Cause the specified cpu to call the generic function handler. -+ */ -+void arch_send_call_function_single_ipi(int cpu) -+{ -+ ipi_send(cpu, IPI_CALL_FUNC_SINGLE); -+} -+ -+/* -+ * setup_profiling_timer() -+ * Dummy function created to keep Oprofile happy in the SMP case. -+ */ -+int setup_profiling_timer(unsigned int multiplier) -+{ -+ return 0; -+} -+ -+/* -+ * smp_mainline_start() -+ * Start a slave thread executing a mainline Linux context. -+ */ -+static void __init smp_mainline_start(void *arg) -+{ -+ int cpuid = smp_processor_id(); -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid); -+ -+ BUG_ON(p->tid != thread_get_self()); -+ -+ /* -+ * Well, support 2.4 linux scheme as well. -+ */ -+ if (cpu_test_and_set(cpuid, cpu_online_map)) { -+ printk(KERN_CRIT "cpu[%d]: already initialized!\n", cpuid); -+ smp_halt_processor(); -+ return; -+ } -+ -+ /* -+ * Initialise the idle task for this CPU -+ */ -+ atomic_inc(&init_mm.mm_count); -+ current->active_mm = &init_mm; -+ if (current->mm) { -+ printk(KERN_CRIT "cpu[%d]: idle task already has memory " -+ "management\n", cpuid); -+ smp_halt_processor(); -+ return; -+ } -+ -+ /* -+ * TODO: X86 does this prior to calling notify, try to understand why? -+ */ -+ preempt_disable(); -+ -+#if defined(CONFIG_GENERIC_CLOCKEVENTS) -+ /* -+ * Setup a local timer event so that this cpu will get timer interrupts -+ */ -+ if (local_timer_setup(cpuid) == -1) { -+ printk(KERN_CRIT "cpu[%d]: timer alloc failed\n", cpuid); -+ smp_halt_processor(); -+ return; -+ } -+#endif -+ -+ /* -+ * Notify those interested that we are up and alive. This must -+ * be done before interrupts are enabled. It must also be completed -+ * before the bootstrap cpu returns from __cpu_up() (see comment -+ * above cpu_set() of the cpu_online_map). -+ */ -+ notify_cpu_starting(cpuid); -+ -+ /* -+ * Indicate that this thread is now online and present. Setting -+ * cpu_online_map has the side effect of allowing the bootstrap -+ * cpu to continue along; so anything that MUST be done prior to the -+ * bootstrap cpu returning from __cpu_up() needs to go above here. -+ */ -+ cpu_set(cpuid, cpu_online_map); -+ cpu_set(cpuid, cpu_present_map); -+ -+ /* -+ * Maintain a thread mapping in addition to the cpu mapping. -+ */ -+ smp_online_threads |= (1 << p->tid); -+ -+ /* -+ * Enable interrupts for this thread. -+ */ -+ local_irq_enable(); -+ -+ /* -+ * Enter the idle loop and wait for a timer to schedule some work. -+ */ -+ printk(KERN_INFO "cpu[%d]: entering cpu_idle()\n", cpuid); -+ cpu_idle(); -+ -+ /* Not Reached */ -+} -+ -+/* -+ * smp_cpus_done() -+ * Called once the kernel_init() has brought up all cpu(s). -+ */ -+void smp_cpus_done(unsigned int cpu_max) -+{ -+ /* Do Nothing */ -+} -+ -+/* -+ * __cpu_up() -+ * Called to startup a sepcific cpu. -+ */ -+int __cpuinit __cpu_up(unsigned int cpu) -+{ -+ struct task_struct *idle; -+ unsigned int *stack; -+ long timeout; -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu); -+ -+ /* -+ * Create an idle task for this CPU. -+ */ -+ idle = fork_idle(cpu); -+ if (IS_ERR(idle)) { -+ panic("cpu[%d]: fork failed\n", cpu); -+ return -ENOSYS; -+ } -+ task_thread_info(idle)->cpu = cpu; -+ -+ /* -+ * Setup the sw_ksp[] to point to this new task. -+ */ -+ sw_ksp[p->tid] = (unsigned int)idle->stack; -+ stack = (unsigned int *)(sw_ksp[p->tid] + PAGE_SIZE - 8); -+ -+ /* -+ * Cause the specified thread to execute our smp_mainline_start -+ * function as a TYPE_NORMAL thread. -+ */ -+ printk(KERN_INFO "cpu[%d]: launching mainline Linux thread\n", cpu); -+ if (thread_start(p->tid, smp_mainline_start, (void *)NULL, stack, -+ THREAD_TYPE_NORMAL) == -1) { -+ printk(KERN_WARNING "cpu[%d]: failed thread_start\n", cpu); -+ return -ENOSYS; -+ } -+ -+ /* -+ * Wait for the thread to start up. The thread will set -+ * the online bit when it is running. Our caller execpts the -+ * cpu to be online if we return 0. -+ */ -+ for (timeout = 0; timeout < 10000; timeout++) { -+ if (cpu_online(cpu)) { -+ break; -+ } -+ -+ udelay(100); -+ barrier(); -+ continue; -+ } -+ -+ if (!cpu_online(cpu)) { -+ printk(KERN_CRIT "cpu[%d]: failed to live after %ld us\n", -+ cpu, timeout * 100); -+ return -ENOSYS; -+ } -+ -+ printk(KERN_INFO "cpu[%d]: came alive after %ld us\n", -+ cpu, timeout * 100); -+ return 0; -+} -+ -+/* -+ * Data used by setup_irq for the IPI. -+ */ -+static struct irqaction ipi_irq = { -+ .name = "ipi", -+ .flags = IRQF_DISABLED | IRQF_PERCPU, -+ .handler = ipi_interrupt, -+}; -+ -+/* -+ * smp_prepare_cpus() -+ * Mark threads that are available to Linux as possible cpus(s). -+ */ -+void __init smp_prepare_cpus(unsigned int max_cpus) -+{ -+ int i; -+ -+ /* -+ * We will need a software IRQ to send IPI(s). We will use -+ * a single software IRQ for all IPI(s). -+ */ -+ if (irq_soft_alloc(&smp_ipi_irq) < 0) { -+ panic("no software IRQ is available\n"); -+ return; -+ } -+ -+ /* -+ * For the IPI interrupt, we want to use our own chip definition. -+ * This allows us to define what happens in SMP IPI without affecting -+ * the performance of the other interrupts. -+ * -+ * Next, Register the IPI interrupt function against the soft IRQ. -+ */ -+ set_irq_chip(smp_ipi_irq, &ubicom32_smp_chip); -+ setup_irq(smp_ipi_irq, &ipi_irq); -+ -+ /* -+ * We use the device tree node to determine how many -+ * free cpus we will have (up to NR_CPUS) and we indicate -+ * that those cpus are present. -+ * -+ * We need to do this very early in the SMP case -+ * because the Linux init code uses the cpu_present_map. -+ */ -+ for_each_possible_cpu(i) { -+ thread_t tid; -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, i); -+ -+ /* -+ * Skip the bootstrap cpu -+ */ -+ if (i == 0) { -+ continue; -+ } -+ -+ /* -+ * If we have a free thread left in the mask, -+ * indicate that the cpu is present. -+ */ -+ tid = thread_alloc(); -+ if (tid == (thread_t)-1) { -+ break; -+ } -+ -+ /* -+ * Save the hardware thread id for this cpu. -+ */ -+ p->tid = tid; -+ cpu_set(i, cpu_present_map); -+ printk(KERN_INFO "cpu[%d]: added to cpu_present_map - tid: %d\n", i, tid); -+ } -+} -+ -+/* -+ * smp_prepare_boot_cpu() -+ * Copy the per_cpu data into the appropriate spot for the bootstrap cpu. -+ * -+ * The code in boot_cpu_init() has already set the boot cpu's -+ * state in the possible, present, and online maps. -+ */ -+void __devinit smp_prepare_boot_cpu(void) -+{ -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0); -+ -+ smp_online_threads |= (1 << p->tid); -+ printk(KERN_INFO "cpu[%d]: bootstrap CPU online - tid: %ld\n", -+ current_thread_info()->cpu, p->tid); -+} -+ -+/* -+ * smp_setup_processor_id() -+ * Set the current_thread_info() structure cpu value. -+ * -+ * We set the value to the true hardware thread value that we are running on. -+ * NOTE: this function overrides the weak alias function in main.c -+ */ -+void __init smp_setup_processor_id(void) -+{ -+ struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0); -+ int i; -+ for_each_cpu_mask(i, CPU_MASK_ALL) -+ set_cpu_possible(i, true); -+ -+ current_thread_info()->cpu = 0; -+ p->tid = thread_get_self(); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/stacktrace.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/stacktrace.c ---- linux-2.6.30.10/arch/ubicom32/kernel/stacktrace.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/stacktrace.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,244 @@ -+/* -+ * arch/ubicom32/kernel/stacktrace.c -+ * Ubicom32 architecture stack back trace implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * These symbols are filled in by the linker. -+ */ -+extern unsigned long _stext; -+extern unsigned long _etext; -+ -+extern unsigned long __ocm_text_run_begin; -+extern unsigned long __data_begin; -+ -+/* -+ * stacktrace_iterate() -+ * Walk the stack looking for call and calli instructions on an aligned -+ * boundary. -+ * -+ * Trace must point to the top of the current stack frame. -+ */ -+unsigned long stacktrace_iterate(unsigned long **trace, -+ unsigned long stext, -+ unsigned long etext, -+ unsigned long ocm_stext, -+ unsigned long ocm_etext, -+ unsigned long sstack, -+ unsigned long estack) -+{ -+ unsigned int thread_trap_en, instruction; -+ unsigned long address; -+ unsigned int limit = 0; -+ unsigned long result = 0; -+ unsigned long *sp = *trace; -+ -+ /* -+ * Exclude the current thread from being monitored for traps. -+ */ -+ asm volatile( -+ " thread_get_self_mask d15 \n\t" -+ /* save current trap status */ -+ " and.4 %0, MT_TRAP_EN, d15 \n\t" -+ " not.4 d15, d15 \n\t" -+ /* disable trap */ -+ " and.4 MT_TRAP_EN, MT_TRAP_EN, d15 \n\t" -+ " pipe_flush 0 \n\t" -+ : "=r" (thread_trap_en) -+ : -+ : "d15", "cc" -+ ); -+ -+ while (limit++ < 256) { -+ /* -+ * See if we have a valid stack. -+ */ -+ if (!between((unsigned long)sp, sstack, estack)) { -+#ifdef TRAP_DEBUG_STACK_TRACE -+ printk(KERN_EMERG "stack address is out of range - " -+ "sp: %x, sstack: %x, estack: %x\n", -+ (unsigned int)sp, (unsigned int)sstack, -+ (unsigned int)estack); -+#endif -+ result = 0; -+ *trace = 0; -+ break; -+ } -+ -+ /* -+ * Get the value off the stack and back up 4 bytes to what -+ * should be the address of a call or calli. -+ */ -+ address = (*sp++) - 4; -+ -+ /* -+ * If the address is not within the text segment, skip this -+ * value. -+ */ -+ if (!between(address, stext, etext) && -+ !between(address, ocm_stext, ocm_etext)) { -+#ifdef TRAP_DEBUG_STACK_TRACE -+ printk(KERN_EMERG "not a text address - " -+ "address: %08x, stext: %08x, etext: %08x\n" -+ "ocm_stext: %08x, ocm_etext: %08x\n", -+ (unsigned int)address, -+ (unsigned int)stext, -+ (unsigned int)etext, -+ (unsigned int)ocm_stext, -+ (unsigned int)ocm_etext); -+#endif -+ continue; -+ -+ } -+ -+ /* -+ * If the address is not on an aligned boundary it can not be a -+ * return address. -+ */ -+ if (address & 0x3) { -+ continue; -+ } -+ -+ /* -+ * Read the probable instruction. -+ */ -+ instruction = *(unsigned int *)address; -+ -+ /* -+ * Is this a call instruction? -+ */ -+ if ((instruction & 0xF8000000) == (u32_t)(0x1B << 27)) { -+#ifdef TRAP_DEBUG_STACK_TRACE -+ printk(KERN_EMERG "call inst. result: %x, " -+ "test: %x\n", (unsigned int)address, -+ (unsigned int)instruction); -+#endif -+ *trace = sp; -+ result = address; -+ break; -+ } -+ -+ /* -+ * Is this a calli instruction? -+ */ -+ if ((instruction & 0xF8000000) == (u32_t)(0x1E << 27)) { -+#ifdef TRAP_DEBUG_STACK_TRACE -+ printk(KERN_EMERG "calli inst. result: %x, " -+ "test: %x\n", (unsigned int)address, -+ (unsigned int)instruction); -+#endif -+ *trace = sp; -+ result = address; -+ break; -+ } -+ } -+ -+ /* -+ * Restore the current thread to be monitored for traps. -+ */ -+ if (thread_trap_en) { -+ asm volatile( -+ " thread_get_self_mask d15 \n\t" -+ " or.4 MT_TRAP_EN, MT_TRAP_EN, d15 \n\t" -+ : -+ : -+ : "d15", "cc" -+ ); -+ } -+ return result; -+} -+ -+#ifdef CONFIG_STACKTRACE -+/* -+ * stacktrace_save_entries() -+ * Save stack back trace information into the provided trace structure. -+ */ -+void stacktrace_save_entries(struct task_struct *tsk, -+ struct stack_trace *trace, -+ unsigned long sp) -+{ -+ unsigned long code_start = (unsigned long)&_stext; -+ unsigned long code_end = (unsigned long)&_etext; -+ unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin; -+ unsigned long ocm_code_end = (unsigned long)&__data_begin; -+ unsigned long stack_end = (unsigned long)(tsk->stack + THREAD_SIZE - 8); -+ unsigned long stack = (unsigned long)sp; -+ unsigned int idx = 0; -+ unsigned long *handle; -+ int skip = trace->skip; -+ -+ handle = (unsigned long *)stack; -+ while (idx < trace->max_entries) { -+ if (skip) { -+ skip--; -+ continue; -+ } -+ trace->entries[idx] = stacktrace_iterate(&handle, -+ code_start, code_end, -+ ocm_code_start, ocm_code_end, -+ (unsigned long)stack, stack_end); -+ if (trace->entries[idx] == 0) { -+ break; -+ } -+ idx++; -+ } -+} -+ -+/* -+ * save_stack_trace() -+ * Save the specified amount of the kernel stack trace information -+ * for the current task. -+ */ -+void save_stack_trace(struct stack_trace *trace) -+{ -+ unsigned long sp = 0; -+ asm volatile ( -+ " move.4 %0, SP \n\t" -+ : "=r" (sp) -+ ); -+ stacktrace_save_entries(current, trace, sp); -+} -+EXPORT_SYMBOL_GPL(save_stack_trace); -+ -+/* -+ * save_stack_trace_tsk() -+ * Save the specified amount of the kernel stack trace information -+ * for the specified task. -+ * -+ * Note: We assume the specified task is not currently running. -+ */ -+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) -+{ -+ stacktrace_save_entries(tsk, trace, tsk->thread.sp); -+} -+EXPORT_SYMBOL_GPL(save_stack_trace_tsk); -+#endif /* CONFIG_STACKTRACE */ -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/syscalltable.S linux-2.6.30.10-ubi/arch/ubicom32/kernel/syscalltable.S ---- linux-2.6.30.10/arch/ubicom32/kernel/syscalltable.S 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/syscalltable.S 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,376 @@ -+/* -+ * arch/ubicom32/kernel/syscalltable.S -+ * -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+/* -+ * -+ * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) -+ * Copyright (C) 1998 D. Jeff Dionne , Kenneth Albanowski , -+ * Copyright (C) 2000 Lineo Inc. (www.lineo.com) -+ * Copyright (C) 1991, 1992 Linus Torvalds -+ */ -+ -+#include -+#include -+#include -+ -+.text -+ALIGN -+ .global sys_call_table -+sys_call_table: -+ .long sys_ni_syscall /* 0 - old "setup()" system call*/ -+ .long sys_exit -+ .long sys_fork -+ .long sys_read -+ .long sys_write -+ .long sys_open /* 5 */ -+ .long sys_close -+ .long sys_waitpid -+ .long sys_creat -+ .long sys_link -+ .long sys_unlink /* 10 */ -+ .long execve_intercept -+ .long sys_chdir -+ .long sys_time -+ .long sys_mknod -+ .long sys_chmod /* 15 */ -+ .long sys_chown16 -+ .long sys_ni_syscall /* old break syscall holder */ -+ .long sys_stat -+ .long sys_lseek -+ .long sys_getpid /* 20 */ -+ .long sys_mount -+ .long sys_oldumount -+ .long sys_setuid16 -+ .long sys_getuid16 -+ .long sys_stime /* 25 */ -+ .long sys_ptrace -+ .long sys_alarm -+ .long sys_fstat -+ .long sys_pause -+ .long sys_utime /* 30 */ -+ .long sys_ni_syscall /* old stty syscall holder */ -+ .long sys_ni_syscall /* old gtty syscall holder */ -+ .long sys_access -+ .long sys_nice -+ .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ -+ .long sys_sync -+ .long sys_kill -+ .long sys_rename -+ .long sys_mkdir -+ .long sys_rmdir /* 40 */ -+ .long sys_dup -+ .long sys_pipe -+ .long sys_times -+ .long sys_ni_syscall /* old prof syscall holder */ -+ .long sys_brk /* 45 */ -+ .long sys_setgid16 -+ .long sys_getgid16 -+ .long sys_signal -+ .long sys_geteuid16 -+ .long sys_getegid16 /* 50 */ -+ .long sys_acct -+ .long sys_umount /* recycled never used phys() */ -+ .long sys_ni_syscall /* old lock syscall holder */ -+ .long sys_ioctl -+ .long sys_fcntl /* 55 */ -+ .long sys_ni_syscall /* old mpx syscall holder */ -+ .long sys_setpgid -+ .long sys_ni_syscall /* old ulimit syscall holder */ -+ .long sys_ni_syscall -+ .long sys_umask /* 60 */ -+ .long sys_chroot -+ .long sys_ustat -+ .long sys_dup2 -+ .long sys_getppid -+ .long sys_getpgrp /* 65 */ -+ .long sys_setsid -+ .long sys_sigaction -+ .long sys_sgetmask -+ .long sys_ssetmask -+ .long sys_setreuid16 /* 70 */ -+ .long sys_setregid16 -+ .long sys_sigsuspend -+ .long sys_sigpending -+ .long sys_sethostname -+ .long sys_setrlimit /* 75 */ -+ .long sys_old_getrlimit -+ .long sys_getrusage -+ .long sys_gettimeofday -+ .long sys_settimeofday -+ .long sys_getgroups16 /* 80 */ -+ .long sys_setgroups16 -+ .long old_select -+ .long sys_symlink -+ .long sys_lstat -+ .long sys_readlink /* 85 */ -+ .long sys_uselib -+ .long sys_ni_syscall /* _sys_swapon */ -+ .long sys_reboot -+ .long sys_old_readdir -+ .long old_mmap /* 90 */ -+ .long sys_munmap -+ .long sys_truncate -+ .long sys_ftruncate -+ .long sys_fchmod -+ .long sys_fchown16 /* 95 */ -+ .long sys_getpriority -+ .long sys_setpriority -+ .long sys_ni_syscall /* old profil syscall holder */ -+ .long sys_statfs -+ .long sys_fstatfs /* 100 */ -+ .long sys_ni_syscall /* ioperm for i386 */ -+ .long sys_socketcall -+ .long sys_syslog -+ .long sys_setitimer -+ .long sys_getitimer /* 105 */ -+ .long sys_newstat -+ .long sys_newlstat -+ .long sys_newfstat -+ .long sys_ni_syscall -+ .long sys_ni_syscall /* iopl for i386 */ /* 110 */ -+ .long sys_vhangup -+ .long sys_ni_syscall /* obsolete idle() syscall */ -+ .long sys_ni_syscall /* vm86old for i386 */ -+ .long sys_wait4 -+ .long sys_ni_syscall /* 115 */ /* _sys_swapoff */ -+ .long sys_sysinfo -+ .long sys_ipc -+ .long sys_fsync -+ .long sys_sigreturn -+ .long clone_intercept /* 120 */ -+ .long sys_setdomainname -+ .long sys_newuname -+ .long sys_cacheflush /* modify_ldt for i386 */ -+ .long sys_adjtimex -+ .long sys_ni_syscall /* 125 */ /* _sys_mprotect */ -+ .long sys_sigprocmask -+ .long sys_ni_syscall /* old "creat_module" */ -+ .long sys_init_module -+ .long sys_delete_module -+ .long sys_ni_syscall /* 130: old "get_kernel_syms" */ -+ .long sys_quotactl -+ .long sys_getpgid -+ .long sys_fchdir -+ .long sys_bdflush -+ .long sys_sysfs /* 135 */ -+ .long sys_personality -+ .long sys_ni_syscall /* for afs_syscall */ -+ .long sys_setfsuid16 -+ .long sys_setfsgid16 -+ .long sys_llseek /* 140 */ -+ .long sys_getdents -+ .long sys_select -+ .long sys_flock -+ .long sys_ni_syscall /* _sys_msync */ -+ .long sys_readv /* 145 */ -+ .long sys_writev -+ .long sys_getsid -+ .long sys_fdatasync -+ .long sys_sysctl -+ .long sys_ni_syscall /* 150 */ /* _sys_mlock */ -+ .long sys_ni_syscall /* _sys_munlock */ -+ .long sys_ni_syscall /* _sys_mlockall */ -+ .long sys_ni_syscall /* _sys_munlockall */ -+ .long sys_sched_setparam -+ .long sys_sched_getparam /* 155 */ -+ .long sys_sched_setscheduler -+ .long sys_sched_getscheduler -+ .long sys_sched_yield -+ .long sys_sched_get_priority_max -+ .long sys_sched_get_priority_min /* 160 */ -+ .long sys_sched_rr_get_interval -+ .long sys_nanosleep -+ .long sys_ni_syscall /* _sys_mremap */ -+ .long sys_setresuid16 -+ .long sys_getresuid16 /* 165 */ -+ .long sys_getpagesize /* _sys_getpagesize */ -+ .long sys_ni_syscall /* old "query_module" */ -+ .long sys_poll -+ .long sys_ni_syscall /* _sys_nfsservctl */ -+ .long sys_setresgid16 /* 170 */ -+ .long sys_getresgid16 -+ .long sys_prctl -+ .long sys_rt_sigreturn -+ .long sys_rt_sigaction -+ .long sys_rt_sigprocmask /* 175 */ -+ .long sys_rt_sigpending -+ .long sys_rt_sigtimedwait -+ .long sys_rt_sigqueueinfo -+ .long sys_rt_sigsuspend -+ .long sys_pread64 /* 180 */ -+ .long sys_pwrite64 -+ .long sys_lchown16 -+ .long sys_getcwd -+ .long sys_capget -+ .long sys_capset /* 185 */ -+ .long sys_sigaltstack -+ .long sys_sendfile -+ .long sys_ni_syscall /* streams1 */ -+ .long sys_ni_syscall /* streams2 */ -+ .long vfork_intercept /* 190 */ -+ .long sys_getrlimit -+ .long sys_mmap2 -+ .long sys_truncate64 -+ .long sys_ftruncate64 -+ .long sys_stat64 /* 195 */ -+ .long sys_lstat64 -+ .long sys_fstat64 -+ .long sys_chown -+ .long sys_getuid -+ .long sys_getgid /* 200 */ -+ .long sys_geteuid -+ .long sys_getegid -+ .long sys_setreuid -+ .long sys_setregid -+ .long sys_getgroups /* 205 */ -+ .long sys_setgroups -+ .long sys_fchown -+ .long sys_setresuid -+ .long sys_getresuid -+ .long sys_setresgid /* 210 */ -+ .long sys_getresgid -+ .long sys_lchown -+ .long sys_setuid -+ .long sys_setgid -+ .long sys_setfsuid /* 215 */ -+ .long sys_setfsgid -+ .long sys_pivot_root -+ .long sys_ni_syscall -+ .long sys_ni_syscall -+ .long sys_getdents64 /* 220 */ -+ .long sys_gettid -+ .long sys_tkill -+ .long sys_setxattr -+ .long sys_lsetxattr -+ .long sys_fsetxattr /* 225 */ -+ .long sys_getxattr -+ .long sys_lgetxattr -+ .long sys_fgetxattr -+ .long sys_listxattr -+ .long sys_llistxattr /* 230 */ -+ .long sys_flistxattr -+ .long sys_removexattr -+ .long sys_lremovexattr -+ .long sys_fremovexattr -+ .long sys_futex /* 235 */ -+ .long sys_sendfile64 -+ .long sys_ni_syscall /* _sys_mincore */ -+ .long sys_ni_syscall /* _sys_madvise */ -+ .long sys_fcntl64 -+ .long sys_readahead /* 240 */ -+ .long sys_io_setup -+ .long sys_io_destroy -+ .long sys_io_getevents -+ .long sys_io_submit -+ .long sys_io_cancel /* 245 */ -+ .long sys_fadvise64 -+ .long sys_exit_group -+ .long sys_lookup_dcookie -+ .long sys_epoll_create -+ .long sys_epoll_ctl /* 250 */ -+ .long sys_epoll_wait -+ .long sys_ni_syscall /* _sys_remap_file_pages */ -+ .long sys_set_tid_address -+ .long sys_timer_create -+ .long sys_timer_settime /* 255 */ -+ .long sys_timer_gettime -+ .long sys_timer_getoverrun -+ .long sys_timer_delete -+ .long sys_clock_settime -+ .long sys_clock_gettime /* 260 */ -+ .long sys_clock_getres -+ .long sys_clock_nanosleep -+ .long sys_statfs64 -+ .long sys_fstatfs64 -+ .long sys_tgkill /* 265 */ -+ .long sys_utimes -+ .long sys_fadvise64_64 -+ .long sys_mbind -+ .long sys_get_mempolicy -+ .long sys_set_mempolicy /* 270 */ -+ .long sys_mq_open -+ .long sys_mq_unlink -+ .long sys_mq_timedsend -+ .long sys_mq_timedreceive -+ .long sys_mq_notify /* 275 */ -+ .long sys_mq_getsetattr -+ .long sys_waitid -+ .long sys_ni_syscall /* for _sys_vserver */ -+ .long sys_add_key -+ .long sys_request_key /* 280 */ -+ .long sys_keyctl -+ .long sys_ioprio_set -+ .long sys_ioprio_get -+ .long sys_inotify_init -+ .long sys_inotify_add_watch /* 285 */ -+ .long sys_inotify_rm_watch -+ .long sys_migrate_pages -+ .long sys_openat -+ .long sys_mkdirat -+ .long sys_mknodat /* 290 */ -+ .long sys_fchownat -+ .long sys_futimesat -+ .long sys_fstatat64 -+ .long sys_unlinkat -+ .long sys_renameat /* 295 */ -+ .long sys_linkat -+ .long sys_symlinkat -+ .long sys_readlinkat -+ .long sys_fchmodat -+ .long sys_faccessat /* 300 */ -+ .long sys_ni_syscall /* Reserved for pselect6 */ -+ .long sys_ni_syscall /* Reserved for ppoll */ -+ .long sys_unshare -+ .long sys_set_robust_list -+ .long sys_get_robust_list /* 305 */ -+ .long sys_splice -+ .long sys_sync_file_range -+ .long sys_tee -+ .long sys_vmsplice -+ .long sys_move_pages /* 310 */ -+ .long sys_sched_setaffinity -+ .long sys_sched_getaffinity -+ .long sys_kexec_load -+ .long sys_getcpu -+ .long sys_epoll_pwait /* 315 */ -+ .long sys_utimensat -+ .long sys_signalfd -+ .long sys_timerfd_create -+ .long sys_eventfd -+ .long sys_fallocate /* 320 */ -+ .long sys_timerfd_settime -+ .long sys_timerfd_gettime -+ .long sys_ni_syscall /* sys_signalfd4 */ -+ .long sys_ni_syscall /* sys_eventfd2 */ -+ .long sys_ni_syscall /* sys_epoll_create1 */ -+ /* 325 */ -+ .long sys_ni_syscall /* sys_dup3 */ -+ .long sys_ni_syscall /* sys_pipe2 */ -+ .long sys_ni_syscall /* sys_inotify_init1 */ -+ .rept NR_syscalls-(.-sys_call_table)/4 -+ .long sys_ni_syscall -+ .endr -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/sys_ubicom32.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/sys_ubicom32.c ---- linux-2.6.30.10/arch/ubicom32/kernel/sys_ubicom32.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/sys_ubicom32.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,237 @@ -+/* -+ * arch/ubicom32/kernel/sys_ubicom32.c -+ * Ubicom32 architecture system call support implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * -+ * This file contains various random system calls that -+ * have a non-standard calling sequence on the Linux/ubicom32 -+ * platform. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* common code for old and new mmaps */ -+static inline long do_mmap2( -+ unsigned long addr, unsigned long len, -+ unsigned long prot, unsigned long flags, -+ unsigned long fd, unsigned long pgoff) -+{ -+ int error = -EBADF; -+ struct file *file = NULL; -+ -+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -+ if (!(flags & MAP_ANONYMOUS)) { -+ file = fget(fd); -+ if (!file) -+ goto out; -+ } -+ -+ down_write(¤t->mm->mmap_sem); -+ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -+ up_write(¤t->mm->mmap_sem); -+ -+ if (file) -+ fput(file); -+out: -+ return error; -+} -+ -+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, -+ unsigned long prot, unsigned long flags, -+ unsigned long fd, unsigned long pgoff) -+{ -+ return do_mmap2(addr, len, prot, flags, fd, pgoff); -+} -+ -+/* -+ * Perform the select(nd, in, out, ex, tv) and mmap() system -+ * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to -+ * handle more than 4 system call parameters, so these system calls -+ * used a memory block for parameter passing.. -+ */ -+ -+struct mmap_arg_struct { -+ unsigned long addr; -+ unsigned long len; -+ unsigned long prot; -+ unsigned long flags; -+ unsigned long fd; -+ unsigned long offset; -+}; -+ -+asmlinkage int old_mmap(struct mmap_arg_struct *arg) -+{ -+ struct mmap_arg_struct a; -+ int error = -EFAULT; -+ -+ if (copy_from_user(&a, arg, sizeof(a))) -+ goto out; -+ -+ error = -EINVAL; -+ if (a.offset & ~PAGE_MASK) -+ goto out; -+ -+ a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -+ -+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, -+ a.offset >> PAGE_SHIFT); -+out: -+ return error; -+} -+ -+struct sel_arg_struct { -+ unsigned long n; -+ fd_set *inp, *outp, *exp; -+ struct timeval *tvp; -+}; -+ -+asmlinkage int old_select(struct sel_arg_struct *arg) -+{ -+ struct sel_arg_struct a; -+ -+ if (copy_from_user(&a, arg, sizeof(a))) -+ return -EFAULT; -+ /* sys_select() does the appropriate kernel locking */ -+ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); -+} -+ -+/* -+ * sys_ipc() is the de-multiplexer for the SysV IPC calls.. -+ * -+ * This is really horribly ugly. -+ */ -+asmlinkage int sys_ipc(uint call, int first, int second, -+ int third, void *ptr, long fifth) -+{ -+ int version, ret; -+ -+ version = call >> 16; /* hack for backward compatibility */ -+ call &= 0xffff; -+ -+ if (call <= SEMCTL) -+ switch (call) { -+ case SEMOP: -+ return sys_semop(first, (struct sembuf *)ptr, second); -+ case SEMGET: -+ return sys_semget(first, second, third); -+ case SEMCTL: { -+ union semun fourth; -+ if (!ptr) -+ return -EINVAL; -+ if (get_user(fourth.__pad, (void **) ptr)) -+ return -EFAULT; -+ return sys_semctl(first, second, third, fourth); -+ } -+ default: -+ return -EINVAL; -+ } -+ if (call <= MSGCTL) -+ switch (call) { -+ case MSGSND: -+ return sys_msgsnd(first, (struct msgbuf *) ptr, -+ second, third); -+ case MSGRCV: -+ switch (version) { -+ case 0: { -+ struct ipc_kludge tmp; -+ if (!ptr) -+ return -EINVAL; -+ if (copy_from_user(&tmp, -+ (struct ipc_kludge *)ptr, -+ sizeof(tmp))) -+ return -EFAULT; -+ return sys_msgrcv(first, tmp.msgp, second, -+ tmp.msgtyp, third); -+ } -+ default: -+ return sys_msgrcv(first, -+ (struct msgbuf *) ptr, -+ second, fifth, third); -+ } -+ case MSGGET: -+ return sys_msgget((key_t) first, second); -+ case MSGCTL: -+ return sys_msgctl(first, second, -+ (struct msqid_ds *) ptr); -+ default: -+ return -EINVAL; -+ } -+ if (call <= SHMCTL) -+ switch (call) { -+ case SHMAT: -+ switch (version) { -+ default: { -+ ulong raddr; -+ ret = do_shmat(first, ptr, second, &raddr); -+ if (ret) -+ return ret; -+ return put_user(raddr, (ulong __user *) third); -+ } -+ } -+ case SHMDT: -+ return sys_shmdt(ptr); -+ case SHMGET: -+ return sys_shmget(first, second, third); -+ case SHMCTL: -+ return sys_shmctl(first, second, ptr); -+ default: -+ return -ENOSYS; -+ } -+ -+ return -EINVAL; -+} -+ -+/* sys_cacheflush -- flush (part of) the processor cache. */ -+asmlinkage int -+sys_cacheflush(unsigned long addr, int scope, int cache, unsigned long len) -+{ -+ flush_cache_all(); -+ return 0; -+} -+ -+asmlinkage int sys_getpagesize(void) -+{ -+ return PAGE_SIZE; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/thread.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/thread.c ---- linux-2.6.30.10/arch/ubicom32/kernel/thread.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/thread.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,228 @@ -+/* -+ * arch/ubicom32/kernel/thread.c -+ * Ubicom32 architecture hardware thread support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * TODO: At some point change the name here to be thread_ksp -+ */ -+unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX]; -+ -+static unsigned int thread_mask = -1; -+static unsigned int thread_mainline_mask; -+ -+/* -+ * thread_entry() -+ * Returning from the called function will disable the thread. -+ * -+ * This could be a naked call to allow for hwthreads that do not have stacks. -+ * However, with -O0, the code still writes to thex stack, and this was -+ * corrupting memory just after the callers stack. -+ */ -+static void thread_entry(void *arg, thread_exec_fn_t exec) -+{ -+ /* -+ * Call thread function -+ */ -+ exec(arg); -+ -+ /* -+ * Complete => Disable self -+ */ -+ thread_disable(thread_get_self()); -+} -+ -+/* -+ * thread_start() -+ * Start the specified function on the specified hardware thread. -+ */ -+thread_t thread_start(thread_t thread, -+ thread_exec_fn_t exec, -+ void *arg, -+ unsigned int *sp_high, -+ thread_type_t type) -+{ -+ /* -+ * Sanity check -+ */ -+ unsigned int enabled, mask, csr; -+ asm volatile ( -+ "move.4 %0, MT_EN\n\t" -+ : "=m" (enabled) -+ ); -+ -+ mask = 1 << thread; -+ if (enabled & mask) { -+ printk(KERN_WARNING "request to enable a previously enabled thread\n"); -+ return (thread_t)-1; -+ } -+ -+ /* -+ * Update thread state -+ */ -+ csr = (thread << 15) | (1 << 14); -+ asm volatile ( -+ "setcsr %0 \n\t" -+ "setcsr_flush 0 \n\t" -+ -+ "move.4 A0, #0 \n\t" -+ "move.4 A1, #0 \n\t" -+ "move.4 A2, #0 \n\t" -+ "move.4 A3, #0 \n\t" -+ "move.4 A4, #0 \n\t" -+ "move.4 A5, #0 \n\t" -+ "move.4 A6, #0 \n\t" -+ "move.4 SP, %4 \n\t" /* A7 is SP */ -+ -+ "move.4 D0, %3 \n\t" -+ "move.4 D1, %2 \n\t" -+ "move.4 D2, #0 \n\t" -+ "move.4 D3, #0 \n\t" -+ "move.4 D4, #0 \n\t" -+ "move.4 D5, #0 \n\t" -+ "move.4 D6, #0 \n\t" -+ "move.4 D7, #0 \n\t" -+ "move.4 D8, #0 \n\t" -+ "move.4 D9, #0 \n\t" -+ "move.4 D10, #0 \n\t" -+ "move.4 D11, #0 \n\t" -+ "move.4 D12, #0 \n\t" -+ "move.4 D13, #0 \n\t" -+ "move.4 D14, #0 \n\t" -+ "move.4 D15, #0 \n\t" -+ -+ "move.4 INT_MASK0, #0 \n\t" -+ "move.4 INT_MASK1, #0 \n\t" -+ "move.4 PC, %1 \n\t" -+ "setcsr #0 \n\t" -+ "setcsr_flush 0 \n\t" -+ : -+ : "r" (csr), "r" (thread_entry), "r" (exec), -+ "r" (arg), "r" (sp_high) -+ ); -+ -+ /* -+ * Apply HRT state -+ */ -+ if (type & THREAD_TYPE_HRT) { -+ asm volatile ( -+ "or.4 MT_HRT, MT_HRT, %0\n\t" -+ : -+ : "d" (mask) -+ : "cc" -+ ); -+ } else { -+ asm volatile ( -+ "and.4 MT_HRT, MT_HRT, %0\n\t" -+ : -+ : "d" (~mask) -+ : "cc" -+ ); -+ } -+ -+ /* -+ * Set priority -+ */ -+ asm volatile ( -+ "or.4 MT_HPRI, MT_HPRI, %0\n\t" -+ : -+ : "d" (mask) -+ : "cc" -+ ); -+ -+ /* -+ * Enable thread -+ */ -+ asm volatile ( -+ "move.4 MT_ACTIVE_SET, %0 \n\t" -+ : -+ : "d" (mask) -+ ); -+ thread_enable_mask(mask); -+ return thread; -+} -+ -+/* -+ * thread_get_mainline() -+ * Return a mask of those threads that are Linux mainline threads. -+ */ -+unsigned int thread_get_mainline(void) -+{ -+ return thread_mainline_mask; -+} -+ -+/* -+ * thread_set_mainline() -+ * Indicate that the specified thread is a Linux mainline thread. -+ */ -+void thread_set_mainline(thread_t tid) -+{ -+ thread_mainline_mask |= (1 << tid); -+} -+ -+/* -+ * thread_alloc() -+ * Allocate an unused hardware thread. -+ */ -+thread_t thread_alloc(void) -+{ -+ thread_t tid; -+ -+ /* -+ * If this is the first time we are here get the list of unused -+ * threads from the processor device tree node. -+ */ -+ if (thread_mask == -1) { -+ thread_mask = processor_threads(); -+ } -+ -+ if (!thread_mask) { -+ return (thread_t)-1; -+ } -+ -+ tid = ffs(thread_mask); -+ if (tid != 0) { -+ tid--; -+ thread_mask &= ~(1 << tid); -+ return tid; -+ } -+ -+ return (thread_t)-1; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/time.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/time.c ---- linux-2.6.30.10/arch/ubicom32/kernel/time.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/time.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,212 @@ -+/* -+ * arch/ubicom32/kernel/time.c -+ * Initialize the timer list and start the appropriate timers. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * A bitmap of the timers on the processor indicates -+ * that the timer is free or in-use. -+ */ -+static unsigned int timers; -+ -+/* -+ * timer_set() -+ * Init the specified compare register to go off cycles from now. -+ */ -+void timer_set(int timervector, unsigned int cycles) -+{ -+ int idx = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector); -+ UBICOM32_IO_TIMER->syscom[idx] = -+ UBICOM32_IO_TIMER->sysval + cycles; -+ ldsr_enable_vector(timervector); -+} -+ -+/* -+ * timer_reset() -+ * Set/reset the timer to go off again. -+ * -+ * Because sysval is a continuous timer, this function is able -+ * to ensure that we do not have clock sku by using the previous -+ * value in syscom to set the next value for syscom. -+ * -+ * Returns the number of ticks that transpired since the last event. -+ */ -+int timer_reset(int timervector, unsigned int cycles) -+{ -+ /* -+ * Reset the timer in the LDSR thread to go off appropriately. -+ * -+ * Use the previous value of the timer to calculate the new stop -+ * time. This allows us to account for it taking an -+ * indeterminate amount of time to get here. -+ */ -+ const int timer_index = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector); -+ unsigned int prev = UBICOM32_IO_TIMER->syscom[timer_index]; -+ unsigned int next = prev + cycles; -+ int scratchpad3; -+ int diff; -+ int ticks = 1; -+ -+ /* -+ * If the difference is negative, we have missed at least one -+ * timer tick. -+ * -+ * TODO: Decide if we want to "ignore" time (as done below) or -+ * if we want to process time (unevenly) by calling timer_tick() -+ * lost_ticks times. -+ */ -+ while (1) { -+ /* -+ * Set our future time first. -+ */ -+ UBICOM32_IO_TIMER->syscom[timer_index] = next; -+ -+ /* -+ * Then check if we are really set time in the futrue. -+ */ -+ diff = (int)next - (int)UBICOM32_IO_TIMER->sysval; -+ if (diff >= 0) { -+ break; -+ } -+ -+ /* -+ * Oops, we are too slow. Playing catch up. -+ * -+ * If the debugger is connected the there is a good -+ * chance that we lost time because we were in a -+ * break-point, so in this case we do not print out -+ * diagnostics. -+ */ -+ asm volatile ("move.4 %0, scratchpad3" -+ : "=r" (scratchpad3)); -+ if ((scratchpad3 & 0x1) == 0) { -+ /* -+ * No debugger attached, print to the console -+ */ -+ printk(KERN_EMERG "diff: %d, timer has lost %u " -+ "ticks [rounded up]\n", -+ -diff, -+ (unsigned int)((-diff + cycles - 1) / cycles)); -+ } -+ -+ do { -+ next += cycles; -+ diff = (int)next - (int)UBICOM32_IO_TIMER->sysval; -+ ticks++; -+ } while (diff < 0); -+ } -+ return ticks; -+} -+ -+/* -+ * sched_clock() -+ * Returns current time in nano-second units. -+ * -+ * Notes: -+ * 1) This is an override for the weak alias in -+ * kernel/sched_clock.c. -+ * 2) Do not use xtime_lock as this function is -+ * sometimes called with xtime_lock held. -+ * 3) We use a retry algorithm to ensure that -+ * we get a consistent value. -+ * 4) sched_clock must be overwritten if IRQ tracing -+ * is enabled because the default implementation uses -+ * the xtime_lock sequence while holding xtime_lock. -+ */ -+unsigned long long sched_clock(void) -+{ -+ unsigned long long my_jiffies; -+ unsigned long jiffies_top; -+ unsigned long jiffies_bottom; -+ -+ do { -+ jiffies_top = jiffies_64 >> 32; -+ jiffies_bottom = jiffies_64 & 0xffffffff; -+ } while (unlikely(jiffies_top != (unsigned long)(jiffies_64 >> 32))); -+ -+ my_jiffies = ((unsigned long long)jiffies_top << 32) | (jiffies_bottom); -+ return (my_jiffies - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ); -+} -+ -+/* -+ * timer_free() -+ * Free a hardware timer. -+ */ -+void timer_free(int interrupt) -+{ -+ unsigned int bit = interrupt - TIMER_INT(0); -+ -+ /* -+ * The timer had not been allocated. -+ */ -+ BUG_ON(timers & (1 << bit)); -+ timers |= (1 << bit); -+} -+ -+/* -+ * timer_alloc() -+ * Allocate a hardware timer. -+ */ -+int timer_alloc(void) -+{ -+ unsigned int bit = find_first_bit((unsigned long *)&timers, 32); -+ if (!bit) { -+ printk(KERN_WARNING "no more free timers\n"); -+ return -1; -+ } -+ -+ timers &= ~(1 << bit); -+ return bit + TIMER_INT(0); -+} -+ -+/* -+ * time_init() -+ * Time init function. -+ */ -+void time_init(void) -+{ -+ /* -+ * Find the processor node and determine what timers are -+ * available for us. -+ */ -+ timers = processor_timers(); -+ if (timers == 0) { -+ printk(KERN_WARNING "no timers are available for Linux\n"); -+ return; -+ } -+ -+#ifdef CONFIG_GENERIC_CLOCKEVENTS -+ timer_device_init(); -+#else -+ timer_tick_init(); -+#endif -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/timer_broadcast.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/timer_broadcast.c ---- linux-2.6.30.10/arch/ubicom32/kernel/timer_broadcast.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/timer_broadcast.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,102 @@ -+/* -+ * arch/ubicom32/kernel/timer_broadcast.c -+ * Implements a dummy clock event for each cpu. -+ * -+ * Copyright (C) 2008 Paul Mundt -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * arch/arm -+ * arch/sh -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); -+ -+/* -+ * The broadcast trick only works when the timer will be used in a periodic mode. -+ * If the user has configured either NO_HZ or HIGH_RES_TIMERS they must have -+ * a per cpu timer. -+ */ -+#if defined(CONFIG_NO_HZ) || defined(CONFIG_HIGH_RES_TIMERS) -+#error "Tickless and High Resolution Timers require per-CPU local timers: CONFIG_LOCAL_TIMERS" -+#endif -+ -+/* -+ * local_timer_interrupt() -+ * Used on SMP for local timer interrupt sent via an IPI. -+ */ -+void local_timer_interrupt(void) -+{ -+ struct clock_event_device *dev = &__get_cpu_var(local_clockevent); -+ -+ dev->event_handler(dev); -+} -+ -+/* -+ * dummy_timer_set_next_event() -+ * Cause the timer to go off "cycles" from now. -+ */ -+static int dummy_timer_set_next_event(unsigned long cycles, struct clock_event_device *dev) -+{ -+ return 0; -+} -+ -+/* -+ * dummy_timer_set_mode() -+ * Do Nothing. -+ */ -+static void dummy_timer_set_mode(enum clock_event_mode mode, -+ struct clock_event_device *clk) -+{ -+} -+ -+/* -+ * local_timer_setup() -+ * Adds a clock event for the specified cpu. -+ */ -+int __cpuinit local_timer_setup(unsigned int cpu) -+{ -+ struct clock_event_device *dev = &per_cpu(local_clockevent, cpu); -+ -+ dev->name = "timer-dummy"; -+ dev->features = CLOCK_EVT_FEAT_DUMMY; -+ dev->rating = 200; -+ dev->mult = 1; -+ dev->set_mode = dummy_timer_set_mode; -+ dev->set_next_event = dummy_timer_set_next_event; -+ dev->broadcast = smp_timer_broadcast; -+ dev->cpumask = cpumask_of_cpu(cpu); -+ dev->irq = -1; -+ printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name); -+ -+ clockevents_register_device(dev); -+ return 0; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/timer_device.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/timer_device.c ---- linux-2.6.30.10/arch/ubicom32/kernel/timer_device.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/timer_device.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,301 @@ -+/* -+ * arch/ubicom32/kernel/timer_device.c -+ * Implements a Ubicom32 clock device and event devices. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if defined(CONFIG_SMP) -+#include -+#endif -+ -+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) -+#define MAX_TIMERS (2 + CONFIG_TIMER_EXTRA_ALLOC) -+#else -+#define MAX_TIMERS (NR_CPUS + CONFIG_TIMER_EXTRA_ALLOC) -+#endif -+ -+#if (MAX_TIMERS > 10) -+#error "Ubicom32 only has 10 timers" -+#endif -+ -+static unsigned int frequency; -+static struct clock_event_device timer_device_devs[MAX_TIMERS]; -+static struct irqaction timer_device_irqs[MAX_TIMERS]; -+static int timer_device_next_timer = 0; -+ -+DEFINE_SPINLOCK(timer_device_lock); -+ -+/* -+ * timer_device_set_next_event() -+ * Cause the timer to go off "cycles" from now. -+ */ -+static int timer_device_set_next_event(unsigned long cycles, struct clock_event_device *dev) -+{ -+ timer_set(dev->irq, cycles); -+ return 0; -+} -+ -+/* -+ * timer_device_set_mode() -+ * Handle the mode switch for a clock event device. -+ */ -+static void timer_device_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) -+{ -+ switch (mode) { -+ case CLOCK_EVT_MODE_SHUTDOWN: -+ /* -+ * Make sure the vector is disabled -+ * until the next event is set. -+ */ -+ printk(KERN_NOTICE "timer[%d]: shutdown\n", dev->irq); -+ ldsr_disable_vector(dev->irq); -+ break; -+ -+ case CLOCK_EVT_MODE_ONESHOT: -+ /* -+ * Make sure the vector is disabled -+ * until the next event is set. -+ */ -+ printk(KERN_NOTICE "timer[%d]: oneshot\n", dev->irq); -+ ldsr_disable_vector(dev->irq); -+ break; -+ -+ case CLOCK_EVT_MODE_PERIODIC: -+ /* -+ * The periodic request is 1 per jiffies -+ */ -+ printk(KERN_NOTICE "timer[%d]: periodic: %d cycles\n", -+ dev->irq, frequency / CONFIG_HZ); -+ timer_set(dev->irq, frequency / CONFIG_HZ); -+ break; -+ -+ case CLOCK_EVT_MODE_UNUSED: -+ case CLOCK_EVT_MODE_RESUME: -+ printk(KERN_WARNING "timer[%d]: unimplemented mode: %d\n", -+ dev->irq, mode); -+ break; -+ }; -+} -+ -+/* -+ * timer_device_event() -+ * Call the device's event handler. -+ * -+ * The pointer is initialized by the generic Linux code -+ * to the function to be called. -+ */ -+static irqreturn_t timer_device_event(int irq, void *dev_id) -+{ -+ struct clock_event_device *dev = (struct clock_event_device *)dev_id; -+ -+ if (dev->mode == CLOCK_EVT_MODE_PERIODIC) { -+ /* -+ * The periodic request is 1 per jiffies -+ */ -+ timer_reset(dev->irq, frequency / CONFIG_HZ); -+ } else { -+ /* -+ * The timer will go off again at the rollover -+ * point. We must disable the IRQ to prevent -+ * getting a spurious interrupt. -+ */ -+ ldsr_disable_vector(dev->irq); -+ } -+ -+ if (!dev->event_handler) { -+ printk(KERN_CRIT "no registered event handler\n"); -+ return IRQ_HANDLED; -+ } -+ -+ dev->event_handler(dev); -+ return IRQ_HANDLED; -+} -+ -+/* -+ * timer_device_clockbase_read() -+ * Provide a primary clocksource around the sysval timer. -+ */ -+static cycle_t timer_device_clockbase_read(void) -+{ -+ return (cycle_t)UBICOM32_IO_TIMER->sysval; -+} -+ -+/* -+ * Primary Clock Source Description -+ * -+ * We use 24 for the shift factor because we want -+ * to ensure there are less than 2^24 clocks -+ * in a jiffie of 10 ms. -+ */ -+static struct clocksource timer_device_clockbase = { -+ .name = "sysval", -+ .rating = 400, -+ .flags = CLOCK_SOURCE_IS_CONTINUOUS, -+ .mask = CLOCKSOURCE_MASK(32), -+ .shift = 24, -+ .mult = 0, -+ .read = timer_device_clockbase_read, -+}; -+ -+/* -+ * timer_device_alloc_event() -+ * Allocate a timer device event. -+ */ -+static int timer_device_alloc_event(const char *name, int cpuid, const cpumask_t *mask) -+{ -+ struct clock_event_device *dev; -+ struct irqaction *action; -+ -+ /* -+ * Are we out of configured timers? -+ */ -+ spin_lock(&timer_device_lock); -+ if (timer_device_next_timer >= MAX_TIMERS) { -+ spin_unlock(&timer_device_lock); -+ printk(KERN_WARNING "out of timer event entries\n"); -+ return -1; -+ } -+ dev = &timer_device_devs[timer_device_next_timer]; -+ action = &timer_device_irqs[timer_device_next_timer]; -+ timer_device_next_timer++; -+ spin_unlock(&timer_device_lock); -+ -+ /* -+ * Now allocate a timer to ourselves. -+ */ -+ dev->irq = timer_alloc(); -+ if (dev->irq == -1) { -+ spin_lock(&timer_device_lock); -+ timer_device_next_timer--; -+ spin_unlock(&timer_device_lock); -+ printk(KERN_WARNING "out of hardware timers\n"); -+ return -1; -+ } -+ -+ /* -+ * Init the IRQ action structure. Make sure -+ * this in place before you register the clock -+ * event device. -+ */ -+ action->name = name; -+ action->flags = IRQF_DISABLED | IRQF_TIMER; -+ action->handler = timer_device_event; -+ cpumask_copy(&action->mask, mask); -+ action->dev_id = dev; -+ setup_irq(dev->irq, action); -+ irq_set_affinity(dev->irq, mask); -+ ldsr_disable_vector(dev->irq); -+ -+ /* -+ * init clock dev structure. -+ * -+ * The min_delta_ns is chosen to ensure that setting next -+ * event will never be requested with too small of value. -+ */ -+ dev->name = name; -+ dev->rating = timer_device_clockbase.rating; -+ dev->shift = timer_device_clockbase.shift; -+ dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; -+ dev->set_mode = timer_device_set_mode; -+ dev->set_next_event = timer_device_set_next_event; -+ dev->mult = div_sc(frequency, NSEC_PER_SEC, dev->shift); -+ dev->max_delta_ns = clockevent_delta2ns(0xffffffff, dev); -+ dev->min_delta_ns = clockevent_delta2ns(100, dev); -+ dev->cpumask = mask; -+ printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name); -+ -+ /* -+ * Now register the device. -+ */ -+ clockevents_register_device(dev); -+ return dev->irq; -+} -+ -+#if defined(CONFIG_LOCAL_TIMERS) -+/* -+ * local_timer_setup() -+ * Allocation function for creating a per cpu local timer. -+ */ -+int __cpuinit local_timer_setup(unsigned int cpu) -+{ -+ return timer_device_alloc_event("timer-cpu", cpu, cpumask_of(cpu)); -+} -+#endif -+ -+/* -+ * timer_device_init() -+ * Create and init a generic clock driver for Ubicom32. -+ */ -+void timer_device_init(void) -+{ -+ int i; -+ -+ /* -+ * Get the frequency from the processor device tree node or use -+ * the default if not available. We will store this as the frequency -+ * of the timer to avoid future calculations. -+ */ -+ frequency = processor_frequency(); -+ if (frequency == 0) { -+ frequency = CLOCK_TICK_RATE; -+ } -+ -+ /* -+ * Setup the primary clock source around sysval. Linux does not -+ * supply a Mhz multiplier so convert down to khz. -+ */ -+ timer_device_clockbase.mult = -+ clocksource_khz2mult(frequency / 1000, -+ timer_device_clockbase.shift); -+ if (clocksource_register(&timer_device_clockbase)) { -+ printk(KERN_ERR "timer: clocksource failed to register\n"); -+ return; -+ } -+ -+ /* -+ * Always allocate a primary timer. -+ */ -+ timer_device_alloc_event("timer-primary", -1, CPU_MASK_ALL_PTR); -+ -+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) -+ /* -+ * If BROADCAST is selected we need to add a broadcast timer. -+ */ -+ timer_device_alloc_event("timer-broadcast", -1, CPU_MASK_ALL_PTR); -+#endif -+ -+ /* -+ * Allocate extra timers that are requested. -+ */ -+ for (i = 0; i < CONFIG_TIMER_EXTRA_ALLOC; i++) { -+ timer_device_alloc_event("timer-extra", -1, CPU_MASK_ALL_PTR); -+ } -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/timer_tick.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/timer_tick.c ---- linux-2.6.30.10/arch/ubicom32/kernel/timer_tick.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/timer_tick.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,109 @@ -+/* -+ * arch/ubicom32/kernel/timer_tick.c -+ * Impelemets a perodic timer. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+ -+#include -+#include -+#if defined(CONFIG_SMP) -+#include -+#endif -+ -+static unsigned int timervector; -+static unsigned int frequency; -+ -+/* -+ * timer_tick() -+ * Kernel system timer support. Needs to keep up the real-time clock, -+ * as well as call the "do_timer()" routine every clocktick. -+ */ -+static irqreturn_t timer_tick(int irq, void *dummy) -+{ -+ int ticks; -+ -+ BUG_ON(!irqs_disabled()); -+ ticks = timer_reset(timervector, frequency); -+ -+ write_seqlock(&xtime_lock); -+ do_timer(ticks); -+ write_sequnlock(&xtime_lock); -+ -+ update_process_times(user_mode(get_irq_regs())); -+ profile_tick(CPU_PROFILING); -+ -+#if defined(CONFIG_SMP) -+ smp_send_timer_all(); -+#endif -+ return(IRQ_HANDLED); -+} -+ -+/* -+ * Data used by setup_irq for the timer. -+ */ -+static struct irqaction timer_irq = { -+ .name = "timer", -+ .flags = IRQF_DISABLED | IRQF_TIMER, -+ .handler = timer_tick, -+}; -+ -+/* -+ * timer_tick_init() -+ * Implements a periodic timer -+ * -+ * This implementation directly calls the timer_tick() and move -+ * the Linux kernel forward. This is used when the user has not -+ * selected GENERIC_CLOCKEVENTS. -+ */ -+void timer_tick_init(void) -+{ -+ /* -+ * Now allocate a timer to ourselves. -+ */ -+ timervector = timer_alloc(); -+ if (timervector == -1) { -+ printk(KERN_WARNING "where did the timer go?\n"); -+ return; -+ } -+ -+ setup_irq(timervector, &timer_irq); -+ -+ /* -+ * Get the frequency from the processor device tree node or use -+ * the default if not available. We will store this as the frequency -+ * of the timer to avoid future calculations. -+ */ -+ frequency = processor_frequency(); -+ if (frequency == 0) { -+ frequency = CLOCK_TICK_RATE; -+ } -+ frequency /= CONFIG_HZ; -+ -+ printk(KERN_NOTICE "timer will interrupt every: %d cycles\n", frequency); -+ timer_set(timervector, frequency); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/topology.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/topology.c ---- linux-2.6.30.10/arch/ubicom32/kernel/topology.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/topology.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,47 @@ -+/* -+ * arch/ubicom32/kernel/topology.c -+ * Ubicom32 architecture sysfs topology information. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+ -+static struct cpu cpu_devices[NR_CPUS] __read_mostly; -+ -+static int __init topology_init(void) -+{ -+ int num; -+ -+ for_each_present_cpu(num) { -+ cpu_devices[num].hotpluggable = 0; -+ register_cpu(&cpu_devices[num], num); -+ } -+ return 0; -+} -+ -+subsys_initcall(topology_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/traps.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/traps.c ---- linux-2.6.30.10/arch/ubicom32/kernel/traps.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/traps.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,514 @@ -+/* -+ * arch/ubicom32/kernel/traps.c -+ * Ubicom32 architecture trap handling support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+/* -+ * Sets up all exception vectors -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define TRAP_MAX_STACK_DEPTH 20 -+ -+/* -+ * These symbols are filled in by the linker. -+ */ -+extern unsigned long _stext; -+extern unsigned long _etext; -+ -+extern unsigned long __ocm_text_run_begin; -+extern unsigned long __data_begin; -+ -+extern void show_vmas(struct task_struct *task); -+ -+const char *trap_cause_strings[] = { -+ /*0*/ "inst address decode error", -+ /*1*/ "inst sync error", -+ /*2*/ "inst illegal", -+ /*3*/ "src1 address decode error", -+ /*4*/ "dst address decode error", -+ /*5*/ "src1 alignment error", -+ /*6*/ "dst alignment error", -+ /*7*/ "src1 sync error", -+ /*8*/ "dst sync error", -+ /*9*/ "DCAPT error", -+ /*10*/ "inst range error", -+ /*11*/ "src1 range error", -+ /*12*/ "dst range error", -+}; -+ -+/* -+ * The device tree trap node definition. -+ */ -+struct trapnode { -+ struct devtree_node dn; -+ unsigned int intthread; -+}; -+ -+static struct trapnode *tn;; -+ -+/* -+ * trap_interrupt_handler() -+ * Software Interrupt to ensure that a trap is serviced. -+ */ -+static irqreturn_t trap_interrupt_handler(int irq, void *dummy) -+{ -+ /* Do Nothing */ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Data used by setup_irq for the timer. -+ */ -+static struct irqaction trap_irq = { -+ .name = "trap", -+ .flags = IRQF_DISABLED, -+ .handler = trap_interrupt_handler, -+}; -+ -+/* -+ * trap_cause_to_str() -+ * Convert a trap_cause into a series of printk -+ */ -+static void trap_cause_to_str(long status) -+{ -+ int bit; -+ -+ if ((status & ((1 << TRAP_CAUSE_TOTAL) - 1)) == 0) { -+ printk(KERN_NOTICE "decode: UNKNOWN CAUSES\n"); -+ return; -+ } -+ -+ for (bit = 0; bit < TRAP_CAUSE_TOTAL; bit++) { -+ if (status & (1 << bit)) { -+ printk(KERN_NOTICE "\tdecode: %08x %s\n", -+ 1 << bit, trap_cause_strings[bit]); -+ } -+ } -+} -+ -+/* -+ * trap_print_information() -+ * Print the cause of the trap and additional info. -+ */ -+static void trap_print_information(const char *str, struct pt_regs *regs) -+{ -+ printk(KERN_WARNING "\n"); -+ -+ if (current) { -+ printk(KERN_WARNING "Process %s (pid: %d)\n", -+ current->comm, current->pid); -+ } -+ -+ if (current && current->mm) { -+ printk(KERN_NOTICE "text = 0x%p-0x%p data = 0x%p-0x%p\n" -+ KERN_NOTICE "bss = 0x%p-0x%p user-stack = 0x%p\n" -+ KERN_NOTICE "\n", -+ (void *)current->mm->start_code, -+ (void *)current->mm->end_code, -+ (void *)current->mm->start_data, -+ (void *)current->mm->end_data, -+ (void *)current->mm->end_data, -+ (void *)current->mm->brk, -+ (void *)current->mm->start_stack); -+ } -+ -+ printk(KERN_WARNING "%s: Causes: 0x%08x\n", str, -+ (unsigned int)regs->trap_cause); -+ trap_cause_to_str(regs->trap_cause); -+ show_regs(regs); -+ show_stack(NULL, (unsigned long *)regs->an[7]); -+ printk(KERN_NOTICE "--- End Trap --- \n"); -+} -+ -+/* -+ * dump_stack() -+ * Dump the stack of the current task. -+ */ -+void dump_stack(void) -+{ -+ show_stack(NULL, NULL); -+} -+EXPORT_SYMBOL(dump_stack); -+ -+/* -+ * show_stack() -+ * Print out information from the current stack. -+ */ -+void show_stack(struct task_struct *task, unsigned long *sp) -+{ -+ /* -+ * Allocate just enough entries on the stack. -+ */ -+ unsigned int calls[TRAP_MAX_STACK_DEPTH]; -+ unsigned long code_start; -+ unsigned long code_end; -+ unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin; -+ unsigned long ocm_code_end = (unsigned long)&__data_begin; -+ unsigned long stack_end = (unsigned long)(current->stack + THREAD_SIZE - 8); -+ unsigned long stack = (unsigned long)sp; -+ int kernel_stack = 1; -+ -+ processor_dram(&code_start, &code_end); -+ -+ /* -+ * Which task are we talking about. -+ */ -+ if (!task) { -+ task = current; -+ } -+ -+ /* -+ * Find the stack for the task if one was not specified. Otherwise -+ * use the specified stack. -+ */ -+ if (!stack) { -+ if (task != current) { -+ stack = task->thread.sp; -+ stack_end = (unsigned long)task->stack + THREAD_SIZE - 8; -+ } else { -+ asm volatile ( -+ "move.4 %0, SP \n\t" -+ : "=r" (stack) -+ ); -+ } -+ } -+ -+ printk(KERN_NOTICE "Starting backtrace: PID %d '%s'\n", -+ task->pid, task->comm); -+ -+ /* -+ * We do 2 passes the first pass is Kernel stack is the second -+ * User stack. -+ */ -+ while (kernel_stack) { -+ unsigned long *handle; -+ unsigned int i, idx = 0; -+ struct pt_regs *pt = task_pt_regs(task); -+ -+ /* -+ * If the task is in user mode, reset the start -+ * and end values for text. -+ */ -+ if (__user_mode(stack)) { -+ if (!(task->personality & FDPIC_FUNCPTRS)) { -+ printk(KERN_NOTICE " User Stack:\n"); -+ code_start = task->mm->start_code; -+ code_end = task->mm->end_code; -+ } else { -+ printk(KERN_NOTICE " User Stack (fdpic):\n"); -+ show_vmas(task); -+ } -+ stack_end = task->mm->start_stack; -+ ocm_code_end = ocm_code_start = 0; -+ kernel_stack = 0; -+ } else { -+ printk(KERN_NOTICE " Kernel Stack:\n"); -+ } -+ -+ /* -+ * Collect the stack back trace information. -+ */ -+ printk(" code[0x%lx-0x%lx]", code_start, code_end); -+ if (ocm_code_start) { -+ printk(" ocm_code[0x%lx-0x%lx]", -+ ocm_code_start, ocm_code_end); -+ } -+ printk("\n stack[0x%lx-0x%lx]\n", stack, stack_end); -+ -+ handle = (unsigned long*)stack; -+ while (idx < TRAP_MAX_STACK_DEPTH) { -+ calls[idx] = stacktrace_iterate(&handle, -+ code_start, code_end, -+ ocm_code_start, ocm_code_end, -+ (unsigned long)stack, stack_end); -+ if (calls[idx] == 0) { -+ break; -+ } -+ idx++; -+ } -+ -+ /* -+ * Now print out the data. -+ */ -+ printk(KERN_NOTICE " CALL && CALLI on stack:"); -+ for (i = 0; i < idx; i++) { -+ printk("%s0x%x, ", (i & 0x3) == 0 ? "\n " : "", -+ calls[i]); -+ } -+ printk(idx == TRAP_MAX_STACK_DEPTH ? "...\n" : "\n"); -+ -+ /* -+ * If we are doing user stack we are done -+ */ -+ if (!kernel_stack) { -+ break; -+ } -+ -+ /* -+ * Does this kernel stack have a mm (i.e. is it user) -+ */ -+ if (!task->mm) { -+ printk("No mm for userspace stack.\n"); -+ break; -+ } -+ /* -+ * Get the user-mode stack (if any) -+ */ -+ stack = pt->an[7]; -+ printk(KERN_NOTICE "Userspace stack at 0x%lx frame type %d\n", -+ stack, (int)pt->frame_type); -+ if (!__user_mode(stack)) { -+ break; -+ } -+ } -+} -+ -+/* -+ * die_if_kernel() -+ * Determine if we are in kernel mode and if so print stuff out and die. -+ */ -+void die_if_kernel(char *str, struct pt_regs *regs, long trap_cause) -+{ -+ unsigned int s3value; -+ -+ if (user_mode(regs)) { -+ return; -+ } -+ -+ console_verbose(); -+ trap_print_information(str, regs); -+ -+ /* -+ * If the debugger is attached via the hardware mailbox protocol, -+ * go into an infinite loop and the debugger will figure things out. -+ */ -+ asm volatile ( -+ "move.4 %0, scratchpad3" -+ : "=r" (s3value) -+ ); -+ if (s3value) { -+ asm volatile("1: jmpt.t 1b"); -+ } -+ -+ /* -+ * Set the debug taint value. -+ */ -+ add_taint(TAINT_DIE); -+ do_exit(SIGSEGV); -+} -+ -+/* -+ * trap_handler() -+ * Handle traps. -+ * -+ * Traps are treated as interrupts and registered with the LDSR. When -+ * the LDSR takes the interrupt, it will determine if a trap has occurred -+ * and service the trap prior to servicing the interrupt. -+ * -+ * This function is directly called by the LDSR. -+ */ -+void trap_handler(int irq, struct pt_regs *regs) -+{ -+ int sig = SIGSEGV; -+ siginfo_t info; -+ unsigned int trap_cause = regs->trap_cause; -+ -+ BUG_ON(!irqs_disabled()); -+ -+ /* -+ * test if in kernel and die. -+ */ -+ die_if_kernel("Kernel Trap", regs, trap_cause); -+ -+ /* -+ * User process problem, setup a signal for this process -+ */ -+ if ((trap_cause & (1 << TRAP_CAUSE_DST_RANGE_ERR)) || -+ (trap_cause & (1 << TRAP_CAUSE_SRC1_RANGE_ERR)) || -+ (trap_cause & (1 << TRAP_CAUSE_I_RANGE_ERR))) { -+ sig = SIGSEGV; -+ info.si_code = SEGV_MAPERR; -+ } else if ((trap_cause & (1 << TRAP_CAUSE_DST_MISALIGNED)) || -+ (trap_cause & (1 << TRAP_CAUSE_SRC1_MISALIGNED))) { -+ sig = SIGBUS; -+ info.si_code = BUS_ADRALN; -+ } else if ((trap_cause & (1 << TRAP_CAUSE_DST_DECODE_ERR)) || -+ (trap_cause & (1 << TRAP_CAUSE_SRC1_DECODE_ERR))) { -+ sig = SIGILL; -+ info.si_code = ILL_ILLOPN; -+ } else if ((trap_cause & (1 << TRAP_CAUSE_ILLEGAL_INST))) { -+ /* -+ * Check for software break point and if found signal trap -+ * not illegal instruction. -+ */ -+ unsigned long instruction; -+ if (between(regs->pc, KERNELSTART, memory_end) && -+ (regs->pc & 3) == 0 && -+ get_user(instruction, (unsigned long *)regs->pc) == 0) { -+ -+ /* -+ * This used to be 0xaabbccdd but it turns out -+ * that is now valid in ubicom32v4 isa so we -+ * have switched to 0xfabbccdd -+ */ -+ if ((instruction == 0xfabbccdd) || -+ (instruction == 0xaabbccdd)) { -+ sig = SIGTRAP; -+ info.si_code = TRAP_BRKPT; -+ goto send_signal; -+ } -+ } -+ sig = SIGILL; -+ info.si_code = ILL_ILLOPC; -+ } else if ((trap_cause & (1 << TRAP_CAUSE_I_DECODE_ERR))) { -+ sig = SIGILL; -+ info.si_code = ILL_ILLOPC; -+ } else if ((trap_cause & (1 << TRAP_CAUSE_DCAPT))) { -+ sig = SIGTRAP; -+ info.si_code = TRAP_TRACE; -+ } -+ -+ /* -+ * Print a trap information block to the console, do not -+ * print this above the case because we don't want it -+ * printed for software break points. -+ */ -+ trap_print_information("User Trap", regs); -+ -+send_signal: -+ -+ force_sig_info(sig, &info, current); -+ -+ /* -+ * Interrupts are disabled, re-enable them now. -+ */ -+ if (!irqs_disabled()) { -+ printk(KERN_EMERG "interrupts enabled on exit, irq=%d, regs=%p", -+ irq, regs); -+ BUG(); -+ } -+} -+ -+/* -+ * trap_init_interrupt() -+ * We need a 2nd trap handling init that will occur after init_IRQ(). -+ */ -+void __init trap_init_interrupt(void) -+{ -+ int err; -+ unsigned char tirq; -+ struct devtree_node *dn = (struct devtree_node *)tn; -+ -+ /* -+ * Now setup the Software IRQ so that if a trap occurs the LDSR -+ * is started. The irq is there just to "force" the LDSR to run. -+ */ -+ if (!tn) { -+ printk(KERN_WARNING "trap_init_interrupt skipped.\n"); -+ return; -+ } -+ -+ err = devtree_irq(dn, NULL, &tirq); -+ if (err) { -+ printk(KERN_WARNING "error obtaining trap irq value: %d\n", -+ err); -+ return; -+ } -+ -+ if (tirq == DEVTREE_IRQ_NONE) { -+ printk(KERN_WARNING "trap irq not available: %d\n", tirq); -+ return; -+ } -+ -+ err = setup_irq(tirq, &trap_irq); -+ if (err) { -+ printk(KERN_WARNING "trap irq setup failed: %d\n", err); -+ return; -+ } -+ -+ /* -+ * Let ultra know which thread is handling the traps and -+ * what the interrupt to use is. -+ */ -+ tn->intthread = ldsr_get_threadid(); -+ -+ /* -+ * Tell the LDSR about our IRQ so that it will unsuspend -+ * if one occurs while waiting for the per thread lock. -+ */ -+ ldsr_set_trap_irq(tirq); -+} -+ -+/* -+ * trap_init() -+ * init trap handling -+ * -+ * Trap handling is done through the ldsr. Every time an interrupt -+ * occurs, the LDSR looks for threads that are listed in the TRAP -+ * register and forces a call to the trap handler. -+ */ -+void __init trap_init(void) -+{ -+ /* -+ * If we do not have a trap node in the device tree, we leave the fault -+ * handling to the underlying hardware. -+ */ -+ tn = (struct trapnode *)devtree_find_node("traps"); -+ if (!tn) { -+ printk(KERN_WARNING "traps are not handled by linux\n"); -+ return; -+ } -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/uaccess.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/uaccess.c ---- linux-2.6.30.10/arch/ubicom32/kernel/uaccess.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/uaccess.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,109 @@ -+/* -+ * arch/ubicom32/include/asm/uaccess.c -+ * User space memory access functions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; -+ -+/* -+ * __access_ok() -+ * Check that the address is in the current processes. -+ * -+ * NOTE: The kernel uses "pretend" user addresses that wind -+ * up calling access_ok() so this approach has only marginal -+ * value because you wind up with lots of false positives. -+ */ -+int __access_ok(unsigned long addr, unsigned long size) -+{ -+ // struct vm_area_struct *vma; -+ -+ /* -+ * Don't do anything if we are not a running system yet. -+ */ -+ if (system_state != SYSTEM_RUNNING) { -+ return 1; -+ } -+ -+ /* -+ * It appears that Linux will call this function even when we are not -+ * in the context of a user space application that has a VM address -+ * space. So we must check that current and mm are valid before -+ * performing the check. -+ */ -+ if ((!current) || (!current->mm)) { -+ return 1; -+ } -+ -+ /* -+ * We perform some basic checks on the address to ensure that it -+ * is at least within the range of DRAM. -+ */ -+ if ((addr < (int)&_etext) || (addr > memory_end)) { -+ printk(KERN_WARNING "pid=%d[%s]: range [%lx - %lx] not in memory area: [%lx - %lx]\n", -+ current->pid, current->comm, -+ addr, addr + size, -+ memory_start, memory_end); -+ return 0; -+ } -+ -+ /* -+ * For nommu Linux we can check this by looking at the allowed -+ * memory map for the process. -+ * -+ * TODO: Since the kernel passes addresses in it's own space as though -+ * they were user address, we can not validate the addresses this way. -+ */ -+#if 0 -+ if (!down_read_trylock(¤t->mm->mmap_sem)) { -+ return 1; -+ } -+ vma = find_vma(current->mm, addr); -+ if (!vma) { -+ up_read(¤t->mm->mmap_sem); -+ printk(KERN_WARNING "pid=%d[%s]: possible invalid acesss on range: [%lx - %lx]\n", -+ current->pid, current->comm, addr, addr + size); -+ return 1; -+ } -+ if ((addr + size) > vma->vm_end) { -+ up_read(¤t->mm->mmap_sem); -+ printk(KERN_WARNING "pid=%d[%s]: possible invalid length on range: [%lx - %lx]\n", -+ current->pid, current->comm, addr, addr + size); -+ return 1; -+ } -+ up_read(¤t->mm->mmap_sem); -+#endif -+ return 1; -+} -+ -+EXPORT_SYMBOL(__access_ok); -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/ubicom32_context_switch.S linux-2.6.30.10-ubi/arch/ubicom32/kernel/ubicom32_context_switch.S ---- linux-2.6.30.10/arch/ubicom32/kernel/ubicom32_context_switch.S 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/ubicom32_context_switch.S 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,359 @@ -+/* -+ * arch/ubicom32/kernel/ubicom32_context_switch.S -+ * Implements context switch and return functions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * begin_restore_context() -+ * Restore most of the context from sp (struct pt_reg *) -+ * -+ * This *can* be called without the global atomic lock. (because sp is -+ * not restored!) Only d15 and a3 are allowed to be used after this -+ * before calling complete_restore_context -+ */ -+.macro begin_restore_context -+ move.4 d0, PT_D0(sp) -+ move.4 d1, PT_D1(sp) -+ move.4 d2, PT_D2(sp) -+ move.4 d3, PT_D3(sp) -+ move.4 d4, PT_D4(sp) -+ move.4 d5, PT_D5(sp) -+ move.4 d6, PT_D6(sp) -+ move.4 d7, PT_D7(sp) -+ move.4 d8, PT_D8(sp) -+ move.4 d9, PT_D9(sp) -+ move.4 d10, PT_D10(sp) -+ move.4 d11, PT_D11(sp) -+ move.4 d12, PT_D12(sp) -+ move.4 d13, PT_D13(sp) -+ move.4 d14, PT_D14(sp) -+;; move.4 d15, PT_D15(sp) -+ move.4 a0, PT_A0(sp) -+ move.4 a1, PT_A1(sp) -+ move.4 a2, PT_A2(sp) -+;; move.4 a3, PT_A3(sp) -+ move.4 a4, PT_A4(sp) -+ move.4 a5, PT_A5(sp) -+ move.4 a6, PT_A6(sp) -+ move.4 acc0_hi, PT_ACC0HI(sp) -+ move.4 acc0_lo, PT_ACC0LO(sp) -+ move.4 mac_rc16, PT_MAC_RC16(sp) -+ move.4 acc1_hi, PT_ACC1HI(sp) -+ move.4 acc1_lo, PT_ACC1LO(sp) -+ move.4 source3, PT_SOURCE3(sp) -+ move.4 int_mask0, PT_INT_MASK0(sp) -+ move.4 int_mask1, PT_INT_MASK1(sp) -+.endm -+ -+/* -+ * complete_restore_context() -+ * Completely restore the context from sp (struct pt_reg *) -+ * -+ * Note: Recovered PC and CSR are saved on the stack and are to be -+ * popped off before returning. -+ */ -+.macro complete_restore_context -+ move.4 a3, sp -+ move.4 d15, PT_D15(sp) -+ move.4 sp, PT_SP(a3) ; Recover Stack pointer from save area -+ move.4 -4(sp)++, PT_PC(a3) ; Recover saved PC and save to stack -+ move.4 -4(sp)++, PT_CSR(a3) ; Recover saved csr and save to stack -+ move.4 a3, PT_A3(a3) -+.endm -+ -+/* -+ * old restore_context macro -+ */ -+.macro restore_context -+ begin_restore_context -+ complete_restore_context -+.endm -+ -+/* -+ * ldsr_thread_enable_interrupts() -+ * An assembly version of the enable interrupts function. -+ * -+ * The stack is fair game but all registers MUST be preserved. -+ * -+ */ -+.macro ldsr_thread_enable_interrupts -+ move.4 -4(sp)++, d3 ; Push d3 -+ move.4 -4(sp)++, a3 ; Push a3 -+ -+ /* -+ * Read the ROSR and obtain ~(1 << tid) -+ */ -+ lsr.4 d3, rosr, #0x2 ; Move the thread portion of ROSR into d3 -+ lsl.4 d3, #1, d3 ; perform a (1 << tid) -+ not.4 d3, d3 ; Negate the value of d3 == ~(1 << threadid) -+ -+ /* -+ * Get the value of the ldsr_soft_irq_mask -+ */ -+ moveai a3, #%hi(ldsr_soft_irq_mask) -+ move.4 a3, %lo(ldsr_soft_irq_mask)(a3) -+ -+ /* -+ * Now re-enable interrupts for this thread and then -+ * wakeup the LDSR. -+ */ -+ and.4 scratchpad1, scratchpad1, d3 -+ move.4 int_set0, a3 -+ -+ /* -+ * Restore the registers. -+ */ -+ move.4 a3, (sp)4++ -+ move.4 d3, (sp)4++ -+.endm -+ -+/* -+ * ret_from_interrupt_to_kernel() -+ * RFI function that is where do_IRQ() returns to if the thread was -+ * in kernel space. -+ */ -+ .section .text.ret_from_interrupt_to_kernel, "ax", @progbits -+ .global ret_from_interrupt_to_kernel -+ret_from_interrupt_to_kernel: -+ begin_restore_context ; Restore the thread context -+ atomic_lock_acquire ; Enter critical section -+ complete_restore_context ; Restore the thread context -+ atomic_lock_release ; Leave critical section -+ ldsr_thread_enable_interrupts ; enable the threads interrupts -+ move.4 csr, (sp)4++ ; Restore csr from the stack -+ ret (sp)4++ -+ -+/* -+ * ret_from_interrupt_to_user() -+ * RFI function that is where do_IRQ() returns to if the thread was -+ * in user space. -+ * -+ * TODO: Do we really need the critical section handling in this code? -+ * -+ */ -+ .section .text.ret_from_interrupt_to_user, "ax", @progbits -+ .global ret_from_interrupt_to_user -+ret_from_interrupt_to_user: -+ ldsr_thread_enable_interrupts ; enable the threads interrupts -+ /* -+ * Set a1 to the thread info pointer, no need to save it as we are -+ * restoring userspace and will never return -+ */ -+ movei d0, #(~(ASM_THREAD_SIZE-1)) -+ and.4 a1, sp, d0 -+ -+ /* -+ * Test if the scheduler needs to be called. -+ */ -+ btst TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED -+ jmpeq.t 2f -+ call a5, schedule ; Call the scheduler. I will come back here. -+ -+ /* -+ * See if we have pending signals and call do_signal -+ * if needed. -+ */ -+2: -+ btst TI_FLAGS(a1), #ASM_TIF_SIGPENDING ; Any signals needed? -+ jmpeq.t 1f -+ -+ /* -+ * Now call do_signal() -+ */ -+ move.4 d0, #0 ; oldset pointer is NULL -+ move.4 d1, sp ; d1 is the regs pointer -+ call a5, do_signal ; Call do_signal() -+ -+ /* -+ * Back from do_signal(), re-enter critical section. -+ */ -+1: -+ begin_restore_context ; Restore the thread context -+ atomic_lock_acquire ; Enter critical section -+ call a3, __complete_and_return_to_userspace ; jump to unprotected section -+ -+/* -+ * restore_all_registers() -+ * -+ * restore_all_registers will be the alternate exit route for -+ * preempted processes that have called a signal handler -+ * and are returning back to user space. -+ */ -+ .section .text.restore_all_registers, "ax", @progbits -+ .global restore_all_registers -+restore_all_registers: -+ begin_restore_context ; Restore the thread context -+ atomic_lock_acquire ; Enter critical section -+ call a3, __complete_and_return_to_userspace -+ -+/* -+ * __complete_and_return_to_userspace -+ * -+ * restores the second half of the context and returns -+ * You must have the atomic lock when you call this function -+ */ -+ .section .kernel_unprotected, "ax", @progbits -+__complete_and_return_to_userspace: -+ disable_kernel_ranges_for_current d15 ; disable kernel ranges -+ complete_restore_context ; restore previous context -+ atomic_lock_release ; Leave critical section -+ move.4 csr, (sp)4++ ; Restore csr from the stack -+ ret (sp)4++ -+ -+/* -+ * ret_from_fork() -+ * Called on the child's return from fork system call. -+ */ -+ .section .text.ret_from_fork, "ax", @progbits -+ .global ret_from_fork -+ret_from_fork: -+ ;;; d0 contains the arg for schedule_tail -+ ;;; the others we don't care about as they are in PT_REGS (sp) -+ call a5, schedule_tail -+ -+ atomic_lock_acquire ; Enter critical section -+ -+ move.4 a3, sp -+ move.4 d0, PT_D0(a3) ; Restore D0 -+ move.4 d1, PT_D1(a3) ; Restore D1 -+ move.4 d2, PT_D2(a3) ; Restore D2 -+ move.4 d3, PT_D3(a3) ; Restore D3 -+ move.4 d10, PT_D10(a3) ; Restore D10 -+ move.4 d11, PT_D11(a3) ; Restore D11 -+ move.4 d12, PT_D12(a3) ; Restore D12 -+ move.4 d13, PT_D13(a3) ; Restore D13 -+ move.4 a1, PT_A1(a3) ; Restore A1 -+ move.4 a2, PT_A2(a3) ; Restore A2 -+ move.4 a5, PT_A5(a3) ; Restore A5 -+ move.4 a6, PT_A6(a3) ; Restore A6 -+ ;; I think atomic_lock_acquire could be moved here.. -+ move.4 sp, PT_SP(a3) ; Restore sp -+ move.4 a4, PT_PC(a3) ; Restore pc in register a4 -+ move.4 PT_FRAME_TYPE(a3), #0 ; Clear frame_type to indicate it is invalid. -+ -+#ifdef CONFIG_PROTECT_KERNEL -+ call a3, __ret_from_fork_bottom_half -+ .section .kernel_unprotected, "ax", @progbits -+__ret_from_fork_bottom_half: -+ disable_kernel_ranges_for_current d15 -+#endif -+ atomic_lock_release ; Leave critical section -+ calli a4, 0(a4) ; Return. -+ -+/* -+ * __switch_to() -+ * -+ * Call with: -+ * void *__switch_to(struct task_struct *prev, struct thread_struct *prev_switch, -+ * struct thread_struct *next_switch) -+ */ -+ .section .text.__switch_to, "ax", @progbits -+ .global __switch_to -+__switch_to: -+ -+ /* -+ * Set up register a3 to point to save area. -+ */ -+ movea a3, d1 ; a3 now holds prev_switch -+ move.4 (a3)4++, d10 -+ move.4 (a3)4++, d11 -+ move.4 (a3)4++, d12 -+ move.4 (a3)4++, d13 -+ move.4 (a3)4++, a1 -+ move.4 (a3)4++, a2 -+ move.4 (a3)4++, a5 -+ move.4 (a3)4++, a6 -+ move.4 (a3)4++, a7 -+ -+ /* -+ * Set up register a3 to point to restore area. -+ */ -+ movea a3, d2 ; a3 now holds next_switch -+ move.4 d10 , (a3)4++ -+ move.4 d11 , (a3)4++ -+ move.4 d12 , (a3)4++ -+ move.4 d13 , (a3)4++ -+ move.4 a1 , (a3)4++ -+ move.4 a2 , (a3)4++ -+ move.4 a5 , (a3)4++ -+ move.4 a6 , (a3)4++ -+ move.4 a7 , (a3)4++ -+ -+ /* -+ * Load the sw_ksp with the proper thread_info pointer. -+ */ -+ movei d15, #(~(ASM_THREAD_SIZE-1)) -+ and.4 a3, sp, d15 ; a3 now has the thread info pointer -+ moveai a4, #%hi(sw_ksp) -+ lea.1 a4, %lo(sw_ksp)(a4) ; a4 now has the base address of sw_ksp array -+ lsr.4 d15, ROSR, #2 ; Thread number - bit's 6 through 31 are zeroes anyway. -+ move.4 (a4, d15), a3 ; Load the thread info pointer into the hw_ksp array.. -+ -+ /* -+ * We are done with context switch. Time to return.. -+ */ -+ calli a5, 0(a5) -+ .size __switch_to, . - __switch_to -+ -+/* -+ * ubicom32_emulate_insn() -+ * Emulates the instruction. -+ * -+ * Call with: -+ * unsigned int ubicom32_emulate_insn(int source1, int source2, int source3, int *save_acc, int *save_csr); -+ */ -+ .section .text.ubicom32_emulate_insn, "ax", @progbits -+ .global ubicom32_emulate_insn -+ .global trap_emulate -+ubicom32_emulate_insn: -+ movea a3, d3 ; a3 holds save_acc pointer -+ movea a4, d4 ; a4 hods save_csr pointer -+ move.4 source3, d2 -+ move.4 acc0_lo, (a3) -+ move.4 acc0_hi, 4(a3) -+ move.4 acc1_lo, 8(a3) -+ move.4 acc1_hi, 12(a3) -+ move.4 mac_rc16, 16(a3) -+ move.4 CSR, (a4) -+ setcsr_flush 0 -+ -+trap_emulate: -+ move.4 d0, d1 -+ setcsr_flush 0 -+ move.4 (a4), CSR ; Save csr -+ move.4 (a3), acc0_lo -+ move.4 4(a3), acc0_hi -+ move.4 8(a3), acc1_lo -+ move.4 12(a3), acc1_hi -+ move.4 16(a3), mac_rc16 -+ ret a5 -+ .size ubicom32_emulate_insn, . - ubicom32_emulate_insn -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/ubicom32_ksyms.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/ubicom32_ksyms.c ---- linux-2.6.30.10/arch/ubicom32/kernel/ubicom32_ksyms.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/ubicom32_ksyms.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,98 @@ -+/* -+ * arch/ubicom32/kernel/ubicom32_ksyms.c -+ * Ubicom32 architecture compiler support and misc symbols. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* platform dependent support */ -+ -+EXPORT_SYMBOL(__ioremap); -+EXPORT_SYMBOL(iounmap); -+ -+EXPORT_SYMBOL(ip_fast_csum); -+ -+ -+/* Networking helper routines. */ -+EXPORT_SYMBOL(csum_partial_copy_nocheck); -+ -+/* The following are special because they're not called -+ explicitly (the C compiler generates them). Fortunately, -+ their interface isn't gonna change any time soon now, so -+ it's OK to leave it out of version control. */ -+EXPORT_SYMBOL(memcpy); -+EXPORT_SYMBOL(memset); -+EXPORT_SYMBOL(memmove); -+ -+#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4 -+/* -+ * libgcc functions - functions that are used internally by the -+ * compiler... (prototypes are not correct though, but that -+ * doesn't really matter since they're not versioned). -+ */ -+extern void __ashldi3(void); -+extern void __ashrdi3(void); -+extern void __divsi3(void); -+extern void __divdi3(void); -+extern void __lshrdi3(void); -+extern void __modsi3(void); -+extern void __muldi3(void); -+extern void __udivsi3(void); -+extern void __umodsi3(void); -+ -+/* gcc lib functions */ -+EXPORT_SYMBOL(__ashldi3); -+EXPORT_SYMBOL(__ashrdi3); -+EXPORT_SYMBOL(__divsi3); -+EXPORT_SYMBOL(__divdi3); -+EXPORT_SYMBOL(__lshrdi3); -+EXPORT_SYMBOL(__modsi3); -+EXPORT_SYMBOL(__muldi3); -+EXPORT_SYMBOL(__udivsi3); -+EXPORT_SYMBOL(__umodsi3); -+#else -+extern void __libgcc_udivmodsi(void); -+extern void __libgcc_divmodsi(void); -+ -+EXPORT_SYMBOL(__libgcc_udivmodsi); -+EXPORT_SYMBOL(__libgcc_divmodsi); -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/ubicom32_syscall.S linux-2.6.30.10-ubi/arch/ubicom32/kernel/ubicom32_syscall.S ---- linux-2.6.30.10/arch/ubicom32/kernel/ubicom32_syscall.S 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/ubicom32_syscall.S 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,694 @@ -+/* -+ * arch/ubicom32/kernel/ubicom32_syscall.S -+ * -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * __old_system_call() -+ */ -+ .section .old_syscall_entry.text, "ax", @progbits -+#ifdef CONFIG_OLD_40400010_SYSTEM_CALL -+__old_system_call: -+ call a3, system_call -+ .size __old_system_call, . - __old_system_call ; -+#else -+ /* -+ * something that will crash the userspace application, but -+ * should not take down the kernel, if protection is enabled -+ * this will never even get executed. -+ */ -+ .long 0xFABBCCDE ; illegal instruction -+ bkpt #-1 ; we will never get here -+#endif -+ -+/* -+ * system_call() -+ */ -+ .section .syscall_entry.text, "ax", @progbits -+ .global system_call -+system_call: -+ /* -+ * Regular ABI rules for function calls apply for syscall. d8 holds -+ * the syscall number. We will use that to index into the syscall table. -+ * d0 - d5 hold the parameters. -+ * -+ * First we get the current thread_info and swap to the kernel stack. -+ * This is done by reading the current thread and looking up the ksp -+ * from the sw_ksp array and storing it in a3. -+ * -+ * Then we reserve space for the syscall context a struct pt_regs and -+ * save it using a4 initially and later as sp. -+ * Once sp is set to the kernel sp we can leave the critical section. -+ * -+ * For the user case the kernel stack will have the following layout. -+ * -+ * a3 ksp[0] +-----------------------+ -+ * | Thread info area | -+ * | struct thread_info | -+ * +-----------------------+ -+ * : : -+ * | Kernel Stack Area | -+ * | | -+ * a4 / sp >>> +-----------------------+ -+ * | Context save area | -+ * | struct pt_reg | -+ * ksp[THREAD_SIZE-8] +-----------------------+ -+ * | 8 Byte Buffer Zone | -+ * ksp[THREAD_SIZE] +-----------------------+ -+ -+ * -+ * For kernel syscalls the layout is as follows. -+ * -+ * a3 ksp[0] +-----------------------+ -+ * | Thread info area | -+ * | struct thread_info | -+ * +-----------------------+ -+ * : : -+ * | Kernel Stack Area | -+ * | | -+ * a4 / sp >>> +-----------------------+ -+ * | Context save area | -+ * | struct pt_reg | -+ * sp at syscall entry +-----------------------+ -+ * | Callers Kernel Stack | -+ * : : -+ * -+ * Once the context is saved we optionally call syscall_trace and setup -+ * the exit routine and jump to the syscall. -+ */ -+ -+ /* -+ * load the base address for sw_ksp into a3 -+ * Note.. we cannot access it just yet as protection is still on. -+ */ -+ moveai a3, #%hi(sw_ksp) -+ lea.1 a3, %lo(sw_ksp)(a3) -+ -+ /* -+ * Enter critical section . -+ * -+ * The 'critical' aspects here are the switching the to the ksp and -+ * changing the protection registers, these both use per thread -+ * information so we need to protect from a context switch. For now this -+ * is done using the global atomic lock. -+ */ -+ atomic_lock_acquire -+ -+ thread_get_self d15 ; Load current thread number -+#ifdef CONFIG_PROTECT_KERNEL -+ lsl.4 d9, #1, d15 ; Convert to thread bit -+ enable_kernel_ranges d9 -+#endif -+ /* -+ * in order to reduce the size of code in the syscall section we get -+ * out of it right now -+ */ -+ call a4, __system_call_bottom_half -+ .size system_call, . - system_call -+ -+ .section .text.__system_call_bottom_half, "ax", @progbits -+__system_call_bottom_half: -+ -+ /* -+ * We need to Determine if this is a kernel syscall or user syscall. -+ * Start by loading the pointer for the thread_info structure for the -+ * current process in to a3. -+ */ -+ move.4 a3, (a3, d15) ; a3 = sw_ksp[d15] -+ -+ /* -+ * Now if this is a kernel thread the same value can be a acheived by -+ * masking off the lower bits on the current stack pointer. -+ */ -+ movei d9, #(~(ASM_THREAD_SIZE-1)) ; load mask -+ and.4 d9, sp, d9 ; apply mask -+ -+ /* -+ * d9 now has the masked version of the sp. If this is identical to -+ * what is in a3 then don't switch to ksp as we are already in the -+ * kernel. -+ */ -+ sub.4 #0, a3, d9 -+ -+ /* -+ * if d9 and a3 are not equal. We are usespace and have to shift to -+ * ksp. -+ */ -+ jmpne.t 1f -+ -+ /* -+ * Kernel Syscall. -+ * -+ * The kernel has called this routine. We have to pdec space for pt_regs -+ * from sp. -+ */ -+ pdec a4, PT_SIZE(sp) ; a4 = ksp - PT_SIZE -+ jmpt.t 2f -+ -+ /* -+ * Userspace Syscall. -+ * -+ * Add THREAD_SIZE and subtract PT_SIZE to create the proper ksp -+ */ -+1: movei d15, #(ASM_THREAD_SIZE - 8 - PT_SIZE) -+ lea.1 a4, (a3, d15) ; a4 = ksp + d15 -+ -+ /* -+ * Replace user stack pointer with kernel stack pointer (a4) -+ * Load -1 into frame_type in save area to indicate this is system call -+ * frame. -+ */ -+2: move.4 PT_A7(a4), a7 ; Save old sp/A7 on kernel stack -+ move.4 PT_FRAME_TYPE(a4), #-1 ; Set the frame type. -+ move.4 sp, a4 ; Change to ksp. -+ /* -+ * We are now officially back in the kernel! -+ */ -+ -+ /* -+ * Now that we are on the ksp we can leave the critical section -+ */ -+ atomic_lock_release -+ -+ /* -+ * We need to save a0 because we need to be able to restore it in -+ * the event that we need to handle a signal. It's not generally -+ * a callee-saved register but is the GOT pointer. -+ */ -+ move.4 PT_A0(sp), a0 ; Save A0 on kernel stack -+ -+ /* -+ * We still need to save d10-d13, a1, a2, a5, a6 in the kernel frame -+ * for this process, we also save the system call params in the case of -+ * syscall restart. (note a7 was saved above) -+ */ -+ move.4 PT_A1(sp), a1 ; Save A1 on kernel stack -+ move.4 PT_A2(sp), a2 ; Save A2 on kernel stack -+ move.4 PT_A5(sp), a5 ; Save A5 on kernel stack -+ move.4 PT_A6(sp), a6 ; Save A6 on kernel stack -+ move.4 PT_PC(sp), a5 ; Save A5 at the PC location -+ move.4 PT_D10(sp), d10 ; Save D10 on kernel stack -+ move.4 PT_D11(sp), d11 ; Save D11 on kernel stack -+ move.4 PT_D12(sp), d12 ; Save D12 on kernel stack -+ move.4 PT_D13(sp), d13 ; Save D13 on kernel stack -+ -+ /* -+ * Now save the syscall parameters -+ */ -+ move.4 PT_D0(sp), d0 ; Save d0 on kernel stack -+ move.4 PT_ORIGINAL_D0(sp), d0 ; Save d0 on kernel stack -+ move.4 PT_D1(sp), d1 ; Save d1 on kernel stack -+ move.4 PT_D2(sp), d2 ; Save d2 on kernel stack -+ move.4 PT_D3(sp), d3 ; Save d3 on kernel stack -+ move.4 PT_D4(sp), d4 ; Save d4 on kernel stack -+ move.4 PT_D5(sp), d5 ; Save d5 on kernel stack -+ move.4 PT_D8(sp), d8 ; Save d8 on kernel stack -+ -+ /* -+ * Test if syscalls are being traced and if they are jump to syscall -+ * trace (it will comeback here) -+ */ -+ btst TI_FLAGS(a3), #ASM_TIF_SYSCALL_TRACE -+ jmpne.f .Lsystem_call__trace -+.Lsystem_call__trace_complete: -+ /* -+ * Check for a valid call number [ 0 <= syscall_number < NR_syscalls ] -+ */ -+ cmpi d8, #0 -+ jmplt.f 3f -+ cmpi d8, #NR_syscalls -+ jmplt.t 4f -+ -+ /* -+ * They have passed an invalid number. Call sys_ni_syscall staring by -+ * load a4 with the base address of sys_ni_syscall -+ */ -+3: moveai a4, #%hi(sys_ni_syscall) -+ lea.1 a4, %lo(sys_ni_syscall)(a4) -+ jmpt.t 5f ; Jump to regular processing -+ -+ /* -+ * Validated syscall, load the syscall table base address into a3 and -+ * read the syscall ptr out. -+ */ -+4: moveai a3, #%hi(sys_call_table) -+ lea.1 a3, %lo(sys_call_table)(a3) ; a3 = sys_call_table -+ move.4 a4, (a3, d8) ; a4 = sys_call_table[d8] -+ -+ /* -+ * Before calling the syscall, setup a5 so that syscall_exit is called -+ * on return from syscall -+ */ -+5: moveai a5, #%hi(syscall_exit) ; Setup return address -+ lea.1 a5, %lo(syscall_exit)(a5) ; from system call -+ -+ /* -+ * If the syscall is __NR_rt_rigreturn then we have to test d1 to -+ * figure out if we have to change change the return routine to restore -+ * all registers. -+ */ -+ cmpi d8, #__NR_rt_sigreturn -+ jmpeq.f 6f -+ -+ /* -+ * Launch system call (it will return through a5 - syscall_exit) -+ */ -+ calli a3, 0(a4) -+ -+ /* -+ * System call is rt_sigreturn. Test d1. If it is 1 we have to -+ * change the return address to restore_all_registers -+ */ -+6: cmpi d1, #1 -+ jmpne.t 7f -+ -+ moveai a5, #%hi(restore_all_registers) ; Setup return address -+ lea.1 a5, %lo(restore_all_registers)(a5) ; to restore_all_registers. -+ -+ /* -+ * Launch system call (it will return through a5) -+ */ -+7: calli a3, 0(a4) ; Launch system call -+ -+.Lsystem_call__trace: -+ /* -+ * Syscalls are being traced. -+ * Call syscall_trace, (return here) -+ */ -+ call a5, syscall_trace -+ -+ /* -+ * Restore syscall state (it would have been discarded during the -+ * syscall trace) -+ */ -+ move.4 d0, PT_D0(sp) ; Restore d0 from kernel stack -+ move.4 d1, PT_D1(sp) ; Restore d1 from kernel stack -+ move.4 d2, PT_D2(sp) ; Restore d2 from kernel stack -+ move.4 d3, PT_D3(sp) ; Restore d3 from kernel stack -+ move.4 d4, PT_D4(sp) ; Restore d4 from kernel stack -+ move.4 d5, PT_D5(sp) ; Restore d5 from kernel stack -+ /* add this back if we ever have a syscall with 7 args */ -+ move.4 d8, PT_D8(sp) ; Restore d8 from kernel stack -+ -+ /* -+ * return to syscall -+ */ -+ jmpt.t .Lsystem_call__trace_complete -+ .size __system_call_bottom_half, . - __system_call_bottom_half -+ -+/* -+ * syscall_exit() -+ */ -+ .section .text.syscall_exit -+ .global syscall_exit -+syscall_exit: -+ /* -+ * d0 contains the return value. We should move that into the kernel -+ * stack d0 location. We will be transitioning from kernel to user -+ * mode. Test the flags and see if we have to call schedule. If we are -+ * going to truly exit then all that has to be done is that from the -+ * kernel stack we have to restore d0, a0, a1, a2, a5, a6 and sp (a7)bb -+ * and then return via a5. -+ */ -+ -+ /* -+ * Save d0 to pt_regs -+ */ -+ move.4 PT_D0(sp), d0 ; Save d0 into the kernel stack -+ -+ /* -+ * load the thread_info structure by masking off the THREAD_SIZE -+ * bits. -+ * -+ * Note: we used to push a1, but now we don't as we are going -+ * to eventually restore it to the userspace a1. -+ */ -+ movei d9, #(~(ASM_THREAD_SIZE-1)) -+ and.4 a1, sp, d9 -+ -+ /* -+ * Are any interesting bits set on TI flags, if there are jump -+ * aside to post_processing. -+ */ -+ move.4 d9, #(_TIF_SYSCALL_TRACE | _TIF_NEED_RESCHED | _TIF_SIGPENDING) -+ and.4 #0, TI_FLAGS(a1), d9 -+ jmpne.f .Lsyscall_exit__post_processing ; jump to handler -+.Lsyscall_exit__post_processing_complete: -+ -+ move.4 d0, PT_D0(sp) ; Restore D0 from kernel stack -+ move.4 d1, PT_D1(sp) ; Restore d1 from kernel stack -+ move.4 d2, PT_D2(sp) ; Restore d2 from kernel stack -+ move.4 d3, PT_D3(sp) ; Restore d3 from kernel stack -+ move.4 d4, PT_D4(sp) ; Restore d4 from kernel stack -+ move.4 d5, PT_D5(sp) ; Restore d5 from kernel stack -+ move.4 d8, PT_D8(sp) ; Restore d8 from kernel stack -+ move.4 d10, PT_D10(sp) ; Restore d10 from kernel stack -+ move.4 d11, PT_D11(sp) ; Restore d11 from kernel stack -+ move.4 d12, PT_D12(sp) ; Restore d12 from kernel stack -+ move.4 d13, PT_D13(sp) ; Restore d13 from kernel stack -+ move.4 a1, PT_A1(sp) ; Restore A1 from kernel stack -+ move.4 a2, PT_A2(sp) ; Restore A2 from kernel stack -+ move.4 a5, PT_A5(sp) ; Restore A5 from kernel stack -+ move.4 a6, PT_A6(sp) ; Restore A6 from kernel stack -+ move.4 a0, PT_A0(sp) ; Restore A6 from kernel stack -+ -+ /* -+ * this is only for debug, and could be removed for production builds -+ */ -+ move.4 PT_FRAME_TYPE(sp), #0 ; invalidate frame_type -+ -+#ifdef CONFIG_PROTECT_KERNEL -+ -+ call a4, __syscall_exit_bottom_half -+ -+ .section .kernel_unprotected, "ax", @progbits -+__syscall_exit_bottom_half: -+ /* -+ * Enter critical section -+ */ -+ atomic_lock_acquire -+ disable_kernel_ranges_for_current d15 -+#endif -+ /* -+ * Lastly restore userspace stack ptr -+ * -+ * Note: that when protection is on we need to hold the lock around the -+ * stack swap as well because otherwise the protection could get -+ * inadvertently disabled again at the end of a context switch. -+ */ -+ move.4 a7, PT_A7(sp) ; Restore A7 from kernel stack -+ -+ /* -+ * We are now officially back in userspace! -+ */ -+ -+#ifdef CONFIG_PROTECT_KERNEL -+ /* -+ * Leave critical section and return to user space. -+ */ -+ atomic_lock_release -+#endif -+ calli a5, 0(a5) ; Back to userspace code. -+ -+ bkpt #-1 ; we will never get here -+ -+ /* -+ * Post syscall processing. (unlikely part of syscall_exit) -+ * -+ * Are we tracing syscalls. If TIF_SYSCALL_TRACE is set, call -+ * syscall_trace routine and return here. -+ */ -+ .section .text.syscall_exit, "ax", @progbits -+.Lsyscall_exit__post_processing: -+ btst TI_FLAGS(a1), #ASM_TIF_SYSCALL_TRACE -+ jmpeq.t 1f -+ call a5, syscall_trace -+ -+ /* -+ * Do we need to resched ie call schedule. If TIF_NEED_RESCHED is set, -+ * call the scheduler, it will come back here. -+ */ -+1: btst TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED -+ jmpeq.t 2f -+ call a5, schedule -+ -+ /* -+ * Do we need to post a signal, if TIF_SIGPENDING is set call the -+ * do_signal. -+ */ -+2: btst TI_FLAGS(a1), #ASM_TIF_SIGPENDING -+ jmpeq.t .Lsyscall_exit__post_processing_complete -+ -+ /* -+ * setup the do signal call -+ */ -+ move.4 d0, #0 ; oldset pointer is NULL -+ lea.1 d1, (sp) ; d1 is the regs pointer. -+ call a5, do_signal -+ -+ jmpt.t .Lsyscall_exit__post_processing_complete -+ -+/* .size syscall_exit, . - syscall_exit */ -+ -+/* -+ * kernel_execve() -+ * kernel_execv is called when we the kernel is starting a -+ * userspace application. -+ */ -+ .section .kernel_unprotected, "ax", @progbits -+ .global kernel_execve -+kernel_execve: -+ move.4 -4(sp)++, a5 ; Save return address -+ /* -+ * Call execve -+ */ -+ movei d8, #__NR_execve ; call execve -+ call a5, system_call -+ move.4 a5, (sp)4++ -+ -+ /* -+ * protection was enabled again at syscall exit, but we want -+ * to return to kernel so we enable it again. -+ */ -+#ifdef CONFIG_PROTECT_KERNEL -+ /* -+ * We are entering the kernel so we need to disable the protection. -+ * Enter critical section, disable ranges and leave critical section. -+ */ -+ call a3, __enable_kernel_ranges ; and jump back to kernel -+#else -+ ret a5 ; jump back to the kernel -+#endif -+ -+ .size kernel_execve, . - kernel_execve -+ -+/* -+ * signal_trampoline() -+ * -+ * Deals with transitioning from to userspace signal handlers and returning -+ * to userspace, only called from the kernel. -+ * -+ */ -+ .section .kernel_unprotected, "ax", @progbits -+ .global signal_trampoline -+signal_trampoline: -+ /* -+ * signal_trampoline is called when we are jumping from the kernel to -+ * the userspace signal handler. -+ * -+ * The following registers are relevant. (set setup_rt_frame) -+ * sp is the user space stack not the kernel stack -+ * d0 = signal number -+ * d1 = siginfo_t * -+ * d2 = ucontext * -+ * d3 = the user space signal handler -+ * a0 is set to the GOT if userspace application is FDPIC, otherwise 0 -+ * a3 is set to the FD for the signal if userspace application is FDPIC -+ */ -+#ifdef CONFIG_PROTECT_KERNEL -+ /* -+ * We are leaving the kernel so we need to enable the protection. -+ * Enter critical section, disable ranges and leave critical section. -+ */ -+ atomic_lock_acquire ; Enter critical section -+ disable_kernel_ranges_for_current d15 ; disable kernel ranges -+ atomic_lock_release ; Leave critical section -+#endif -+ /* -+ * The signal handler pointer is in register d3 so tranfer it to a4 and -+ * call it -+ */ -+ movea a4, d3 ; signal handler -+ calli a5, 0(a4) -+ -+ /* -+ * Return to userspace through rt_syscall which is stored on top of the -+ * stack d1 contains ret_via_interrupt status. -+ */ -+ move.4 d8, (sp) ; d8 (syscall #) = rt_syscall -+ move.4 d1, 4(sp) ; d1 = ret_via_interrupt -+ call a5, system_call ; as we are 'in' the kernel -+ ; we can call kernel_syscall -+ -+ bkpt #-1 ; will never get here. -+ .size signal_trampoline, . - signal_trampoline -+ -+/* -+ * kernel_thread_helper() -+ * -+ * Entry point for kernel threads (only referenced by kernel_thread()). -+ * -+ * On execution d0 will be 0, d1 will be the argument to be passed to the -+ * kernel function. -+ * d2 contains the kernel function that needs to get called. -+ * d3 will contain address to do_exit which needs to get moved into a5. -+ * -+ * On return from fork the child thread d0 will be 0. We call this dummy -+ * function which in turn loads the argument -+ */ -+ .section .kernel_unprotected, "ax", @progbits -+ .global kernel_thread_helper -+kernel_thread_helper: -+ /* -+ * Create a kernel thread. This is called from ret_from_vfork (a -+ * userspace return routine) so we need to put it in an unprotected -+ * section and re-enable protection before calling the vector in d2. -+ */ -+ -+#ifdef CONFIG_PROTECT_KERNEL -+ /* -+ * We are entering the kernel so we need to disable the protection. -+ * Enter critical section, disable ranges and leave critical section. -+ */ -+ call a5, __enable_kernel_ranges -+#endif -+ /* -+ * Move argument for kernel function into d0, and set a5 return address -+ * (a5) to do_exit and return through a2 -+ */ -+ move.4 d0, d1 ; d0 = arg -+ move.4 a5, d3 ; a5 = do_exit -+ ret d2 ; call function ptr in d2 -+ .size kernel_thread_helper, . - kernel_thread_helper -+ -+#ifdef CONFIG_PROTECT_KERNEL -+ .section .kernel_unprotected, "ax", @progbits -+__enable_kernel_ranges: -+ atomic_lock_acquire ; Enter critical section -+ enable_kernel_ranges_for_current d15 -+ atomic_lock_release ; Leave critical section -+ calli a5, 0(a5) -+ .size __enable_kernel_ranges, . - __enable_kernel_ranges -+ -+#endif -+ -+/* -+ * The following system call intercept functions where we setup the -+ * input to the real system call. In all cases these are just taking -+ * the current sp which is pointing to pt_regs and pushing it into the -+ * last arg of the system call. -+ * -+ * i.e. the public definition of sys_execv is -+ * sys_execve( char *name, -+ * char **argv, -+ * char **envp ) -+ * but process.c defines it as -+ * sys_execve( char *name, -+ * char **argv, -+ * char **envp, -+ * struct pt_regs *regs ) -+ * -+ * so execve_intercept needs to populate the 4th arg with pt_regs*, -+ * which is the stack pointer as we know we must be coming out of -+ * system_call -+ * -+ * The intercept vectors are referenced by syscalltable.S -+ */ -+ -+/* -+ * execve_intercept() -+ */ -+ .section .text.execve_intercept, "ax", @progbits -+ .global execve_intercept -+execve_intercept: -+ move.4 d3, sp ; Save pt_regs address -+ call a3, sys_execve -+ -+ .size execve_intercept, . - execve_intercept -+ -+/* -+ * vfork_intercept() -+ */ -+ .section .text.vfork_intercept, "ax", @progbits -+ .global vfork_intercept -+vfork_intercept: -+ move.4 d0, sp ; Save pt_regs address -+ call a3, sys_vfork -+ -+ .size vfork_intercept, . - vfork_intercept -+ -+/* -+ * clone_intercept() -+ */ -+ .section .text.clone_intercept, "ax", @progbits -+ .global clone_intercept -+clone_intercept: -+ move.4 d2, sp ; Save pt_regs address -+ call a3, sys_clone -+ -+ .size clone_intercept, . - clone_intercept -+ -+/* -+ * sys_sigsuspend() -+ */ -+ .section .text.sigclone_intercept, "ax", @progbits -+ .global sys_sigsuspend -+sys_sigsuspend: -+ move.4 d0, sp ; Pass pointer to pt_regs in d0 -+ call a3, do_sigsuspend -+ -+ .size sys_sigsuspend, . - sys_sigsuspend -+ -+/* -+ * sys_rt_sigsuspend() -+ */ -+ .section .text.sys_rt_sigsuspend, "ax", @progbits -+ .global sys_rt_sigsuspend -+sys_rt_sigsuspend: -+ move.4 d0, sp ; Pass pointer to pt_regs in d0 -+ call a3, do_rt_sigsuspend -+ -+ .size sys_rt_sigsuspend, . - sys_rt_sigsuspend -+ -+/* -+ * sys_rt_sigreturn() -+ */ -+ .section .text.sys_rt_sigreturn, "ax", @progbits -+ .global sys_rt_sigreturn -+sys_rt_sigreturn: -+ move.4 d0, sp ; Pass pointer to pt_regs in d0 -+ call a3, do_rt_sigreturn -+ -+ .size sys_rt_sigreturn, . - sys_rt_sigreturn -+ -+/* -+ * sys_sigaltstack() -+ */ -+ .section .text.sys_sigaltstack, "ax", @progbits -+ .global sys_sigaltstack -+sys_sigaltstack: -+ move.4 d0, sp ; Pass pointer to pt_regs in d0 -+ call a3, do_sys_sigaltstack -+ -+ .size sys_sigaltstack, . - sys_sigaltstack -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/unaligned_trap.c linux-2.6.30.10-ubi/arch/ubicom32/kernel/unaligned_trap.c ---- linux-2.6.30.10/arch/ubicom32/kernel/unaligned_trap.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/unaligned_trap.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,698 @@ -+/* -+ * arch/ubicom32/kernel/unaligned_trap.c -+ * Handle unaligned traps in both user or kernel space. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#define FALSE 0 -+#define TRUE 1 -+ -+/* no possible trap */ -+#define UNUSED 0 -+/* possible source operand trap */ -+#define SRC 1 -+#define SRC_2 2 -+/* possible destination operand trap */ -+#define DEST 3 -+#define DEST_2 4 -+/* can be either source or destination or both */ -+#define TWO_OP 5 -+#define TWO_OP_2 6 -+ -+/* TODO: What is the real value here, put something in to make it compile for -+ * now */ -+#define MOVE_2 0x0d -+#define LSL_2 0x11 -+#define LSR_2 0x13 -+#define MOVEI 0x19 -+#define CMPI 0x18 -+ -+static int op_format[32] = -+{ -+ TWO_OP, /* 0x00 */ -+ UNUSED, -+ SRC, -+ UNUSED, -+ TWO_OP, /* 0x04 */ -+ TWO_OP, -+ SRC, -+ UNUSED, -+ TWO_OP_2, /* 0x08 */ -+ TWO_OP, -+ TWO_OP_2, -+ TWO_OP, -+ TWO_OP_2, /* 0x0C */ -+ TWO_OP, -+ TWO_OP_2, -+ TWO_OP, -+ TWO_OP, /* 0x10 */ -+ TWO_OP_2, -+ TWO_OP, -+ TWO_OP, -+ UNUSED, /* 0x14 */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ SRC_2, /* 0x18 */ -+ DEST_2, -+ UNUSED, -+ UNUSED, -+ UNUSED, /* 0x1C */ -+ UNUSED, -+ UNUSED, /* unaligned CALLI will not be fixed. */ -+ UNUSED -+}; -+ -+static int op_0_format[32] = -+{ -+ UNUSED, /* 0x00 */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ UNUSED, /* 0x04 - ret don't fix - bad ret is always wrong */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ UNUSED, /* 0x08 */ -+ UNUSED, -+ TWO_OP, -+ TWO_OP_2, -+ TWO_OP, /* 0x0c */ -+ TWO_OP_2, -+ TWO_OP, -+ UNUSED, /* .1 can't trap */ -+ UNUSED, /* 0x10 */ -+ UNUSED, -+ SRC, -+ UNUSED, -+ UNUSED, /* 0x14 */ -+ TWO_OP_2, -+ UNUSED, -+ UNUSED, -+ UNUSED, /* 0x18 */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ DEST, /* 0x1c */ -+ DEST, -+ DEST, -+ DEST, /* all lea have 32-bit destination */ -+}; -+ -+static int op_2_format[32] = -+{ -+ UNUSED, /* 0x00 */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ UNUSED, /* 0x04 */ -+ UNUSED, -+ SRC, -+ UNUSED, -+ UNUSED, /* 0x08 crcgen is .1 */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ UNUSED, /* 0x0c */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ SRC, /* 0x10 */ -+ SRC_2, -+ SRC, -+ SRC_2, -+ SRC, /* 0x14 */ -+ SRC_2, -+ SRC, -+ UNUSED, -+ UNUSED, /* 0x18 */ -+ UNUSED, -+ SRC, -+ UNUSED, -+ SRC, /* 0x1c */ -+ UNUSED, -+ SRC_2, -+ UNUSED, -+}; -+ -+static int op_6_format[32] = -+{ -+ SRC_2, /* 0x00 */ -+ SRC_2, -+ SRC_2, -+ SRC_2, -+ SRC_2, /* 0x04 */ -+ SRC_2, -+ UNUSED, -+ SRC_2, -+ SRC, /* 0x08 MULS.4 */ -+ SRC_2, -+ SRC, -+ UNUSED, -+ UNUSED, /* 0x0c */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ SRC, /* 0x10 */ -+ SRC_2, -+ SRC, -+ SRC_2, -+ UNUSED, /* 0x14 */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ UNUSED, /* 0x18 */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+ UNUSED, /* 0x1c */ -+ UNUSED, -+ UNUSED, -+ UNUSED, -+}; -+ -+/* -+ * unaligned_get_address() -+ * get an address using save_an and save_dn registers, and updates save_an -+ * with side effects -+ */ -+unsigned char *unaligned_get_address(int thread, int specifier, int four_byte, -+ unsigned int save_an[], -+ unsigned int save_dn[], int *write_back_an) -+{ -+ unsigned char *address; -+ -+ int areg = (specifier >> 5) & 7; -+ if ((specifier >> 8) == 2) { -+ int offset = specifier & 0xf; -+ offset = ((offset << 28) >> 28); -+ if (likely(four_byte)) { -+ offset <<= 2; -+ } else { -+ offset <<= 1; -+ } -+ if (specifier & 0x10) { -+ address = (unsigned char *)(save_an[areg] + offset); -+ } else { -+ address = (unsigned char *)save_an[areg]; -+ } -+ save_an[areg] = save_an[areg] + offset; -+ -+ /* -+ * Let caller know An registers have been modified. -+ */ -+ *write_back_an = 1; -+ } else if ((specifier >> 8) == 3) { -+ int dreg = specifier & 0xf; -+ if (likely(four_byte)) { -+ address = (unsigned char *)(save_an[areg] + -+ (save_dn[dreg] << 2)); -+ } else { -+ address = (unsigned char *)(save_an[areg] + -+ (save_dn[dreg] << 1)); -+ } -+ } else { -+ int offset = ((specifier >> 3) & 0x60) | (specifier & 0x1f); -+ if (likely(four_byte)) { -+ address = (unsigned char *)(save_an[areg] + -+ (offset << 2)); -+ } else { -+ address = (unsigned char *)(save_an[areg] + -+ (offset << 1)); -+ } -+ } -+ -+ return address; -+} -+ -+static int save_dn[16]; -+static int save_an[8]; -+static int save_acc[5]; -+ -+/* -+ * unaligned_emulate() -+ * emulate the instruction at thread's pc that has taken an unaligned data -+ * trap. -+ * -+ * source or destination or both might be unaligned -+ * the instruction must have a memory source or destination or both -+ * the emulated instruction is copied and executed in this thread -+ * -+ * TODO: Protection is handled outside of this function -+ * TODO: handling simultaneous unaligned and memory protection traps -+ * -+ * Get thread state -+ * the PC and instruction (and local copy, emulate_inst), and An -+ * and Dn registers -+ * All implicit soruce state (source3, CSR, accumulators) -+ -+ * if the instruction has a memory source -+ * Use the instruction, An and Dn registers to form src_address -+ * get unaligned source data from src_address (usually sign -+ * extended) -+ * (2 bytes, with or without sign extension, or 4 bytes) -+ * modify emulate_inst to use d0 as source -+ * else -+ * get the soure operand from one of thread's registers -+ * if instruction has a memory destination -+ * Use the instruction, An and Dn registers to form dest_address -+ * modify emulate_inst to use d0 as destination -+ * if there was a memory source -+ * put the source data in thread's d0 -+ * get the source-2 Dn operand and source 3 operand from thread -+ * execute modified inst -+ * (save it, flush caches, set up local values for implicit -+ * sources, execute, save explicit and implicit results) -+ * if inst has destination address -+ * copy result to dest_address, possibly unaligned, 1, 2, or 4 -+ * bytes -+ * restore thread's implicit results (modified address registers, CSR, -+ * accumulators) add 4 to thread's pc -+ */ -+void unaligned_emulate(unsigned int thread) -+{ -+ unsigned int pc; -+ unsigned int inst; -+ unsigned int op; -+ unsigned int subop; -+ int format; -+ unsigned int emulate_inst; -+ int four_byte; -+ int src_operand, dest_operand; -+ int save_csr; -+ int source3; -+ unsigned int source1; -+ unsigned int source_data; -+ unsigned char *dest_address = NULL; -+ int source2 = 0; -+ unsigned int result; -+ unsigned int write_back_an = 0; -+ unsigned int chip_id_copy; -+ -+ extern unsigned int trap_emulate; -+ extern unsigned int ubicom32_emulate_insn(int source1, int source2, -+ int source3, int *save_acc, -+ int *save_csr); -+ -+ /* -+ * get the chip_id -+ */ -+ asm volatile ( -+ " move.4 %0, chip_id \n\t" /* get chip_id. */ -+ : "=r"(chip_id_copy) -+ : -+ ); -+ -+ /* -+ * get the pc -+ */ -+ asm volatile ( -+ " move.4 CSR, %1 \n\t" /* set source thread in -+ * CSR */ -+ " setcsr_flush 0 \n\t" -+ " move.4 %0, pc \n\t" -+ " move.4 CSR, #0 \n\t" /* restore CSR */ -+ " setcsr_flush 0 \n\t" -+ : "=a"(pc) -+ : "d" ((1 << 8) | (thread << 9)) -+ : "cc" -+ ); -+ -+ inst = *((unsigned int *)pc); -+ op = inst >> 27; -+ if (unlikely(op == 2 || op == 6)) { -+ subop = (inst >> 21) & 0x1f; -+ } else { -+ subop = (inst >> 11) & 0x1f; -+ } -+ format = op_format[op]; -+ emulate_inst = inst; -+ -+ if (op == 0) { -+ format = op_0_format[subop]; -+ } else if (op == 2) { -+ format = op_2_format[subop]; -+ } else if (op == 6) { -+ format = op_6_format[subop]; -+ } -+ -+ if (unlikely(format == UNUSED)) { -+ /* -+ * We are not going to emulate this. Bump PC by 4 and move on. -+ */ -+ asm volatile ( -+ " move.4 CSR, %0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " move.4 pc, %1 \n\t" -+ " setcsr #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ : -+ : "d"((1 << 14) | (thread << 15)), "d"(pc + 4) -+ : "cc" -+ ); -+ return; -+ } -+ -+ four_byte = (format == TWO_OP || format == DEST || format == SRC); -+ -+ /* -+ * source or destination memory operand needs emulation -+ */ -+ src_operand = (format == SRC || -+ format == SRC_2 || -+ format == TWO_OP || -+ format == TWO_OP_2) && -+ ((inst >> 8) & 7) > 1; -+ -+ dest_operand = (format == DEST || -+ format == DEST_2 || -+ format == TWO_OP || -+ format == TWO_OP_2) && -+ ((inst >> 24) & 7) > 1; -+ -+ /* -+ * get thread's implicit sources (not covered by source context select). -+ * data and address registers and CSR (for flag bits) and src3 and -+ * accumulators -+ */ -+ asm volatile ( -+ " move.4 CSR, %2 \n\t" /* set source thread in -+ * CSR */ -+ " setcsr_flush 0 \n\t" -+ " move.4 (%3), d0 \n\t" /* get dn registers */ -+ " move.4 4(%3), d1 \n\t" -+ " move.4 8(%3), d2 \n\t" -+ " move.4 12(%3), d3 \n\t" -+ " move.4 16(%3), d4 \n\t" -+ " move.4 20(%3), d5 \n\t" -+ " move.4 24(%3), d6 \n\t" -+ " move.4 28(%3), d7 \n\t" -+ " move.4 32(%3), d8 \n\t" -+ " move.4 36(%3), d9 \n\t" -+ " move.4 40(%3), d10 \n\t" -+ " move.4 44(%3), d11 \n\t" -+ " move.4 48(%3), d12 \n\t" -+ " move.4 52(%3), d13 \n\t" -+ " move.4 56(%3), d14 \n\t" -+ " move.4 60(%3), d15 \n\t" -+ " move.4 (%4), a0 \n\t" /* get an registers */ -+ " move.4 4(%4), a1 \n\t" -+ " move.4 8(%4), a2 \n\t" -+ " move.4 12(%4), a3 \n\t" -+ " move.4 16(%4), a4 \n\t" -+ " move.4 20(%4), a5 \n\t" -+ " move.4 24(%4), a6 \n\t" -+ " move.4 28(%4), a7 \n\t" -+ " move.4 %0, CSR \n\t" /* get csr and source3 -+ * implicit operands */ -+ " move.4 %1, source3 \n\t" -+ " move.4 (%5), acc0_lo \n\t" /* get accumulators */ -+ " move.4 4(%5), acc0_hi \n\t" -+ " move.4 8(%5), acc1_lo \n\t" -+ " move.4 12(%5), acc1_hi \n\t" -+ " move.4 16(%5), mac_rc16 \n\t" -+ " move.4 CSR, #0 \n\t" /* restore CSR */ -+ " setcsr_flush 0 \n\t" -+ : "=m"(save_csr), "=m"(source3) -+ : "d"((1 << 8) | (thread << 9)), -+ "a"(save_dn), "a"(save_an), "a"(save_acc) -+ : "cc" -+ ); -+ -+ /* -+ * turn off thread select bits if they were on -+ */ -+ BUG_ON((save_csr & 0x04100) != 0); -+ if (unlikely(save_csr & 0x04100)) { -+ /* -+ * Things are in funny state as thread select bits are on in -+ * csr. PANIC. -+ */ -+ panic("In unaligned trap handler. Trap thread CSR has thread " -+ "select bits on.\n"); -+ } -+ -+ save_csr = save_csr & 0x1000ff; -+ -+ /* -+ * get the source1 operand -+ */ -+ source1 = 0; -+ if (src_operand) { -+ unsigned char *src_address; -+ -+ /* -+ * source1 comes from memory -+ */ -+ BUG_ON(!(format == TWO_OP || format == TWO_OP_2 || -+ format == SRC || format == SRC_2)); -+ src_address = unaligned_get_address(thread, inst & 0x7ff, -+ four_byte, save_an, -+ save_dn, &write_back_an); -+ -+ /* -+ * get data (possibly unaligned) -+ */ -+ if (likely(four_byte)) { -+ source_data = (*src_address << 24) | -+ (*(src_address + 1) << 16) | -+ (*(src_address + 2) << 8) | -+ *(src_address + 3); -+ source1 = source_data; -+ } else { -+ source1 = *src_address << 8 | -+ *(src_address + 1); -+ -+ /* -+ * Source is not extended if the instrution is MOVE.2 or -+ * if the cpu CHIP_ID >= 0x30000 and the instruction is -+ * either LSL.2 or LSR.2. All other cases have to be -+ * sign extended. -+ */ -+ if ((!(op == 2 && subop == MOVE_2)) && -+ (!((chip_id_copy >= 0x30000) && -+ (subop == LSL_2 || subop == LSR_2)))) { -+ /* -+ * Have to sign extend the .2 entry. -+ */ -+ source1 = ((unsigned int) -+ ((signed int) -+ ((signed short) source1))); -+ } -+ } -+ } else if (likely(op != MOVEI)) { -+ /* -+ * source1 comes from a register, using move.4 d0, src1 -+ * unaligned_emulate_get_source is pointer to code to insert remulated instruction -+ */ -+ extern unsigned int unaligned_emulate_get_src; -+ *((int *)&unaligned_emulate_get_src) &= ~(0x7ff); -+ *((int *)&unaligned_emulate_get_src) |= (inst & 0x7ff); -+ flush_dcache_range((unsigned long)(&unaligned_emulate_get_src), -+ (unsigned long)(&unaligned_emulate_get_src) + 4); -+ -+ asm volatile ( -+ /* source1 uses thread's registers */ -+ " move.4 CSR, %1 \n\t" -+ " setcsr_flush 0 \n\t" -+ "unaligned_emulate_get_src: \n\t" -+ " move.4 %0, #0 \n\t" -+ " setcsr #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ : "=d" (source1) -+ : "d" ((1 << 8) | (thread << 9)) -+ : "cc" -+ ); -+ } -+ -+ /* -+ * get the destination address -+ */ -+ if (dest_operand) { -+ BUG_ON(!(format == TWO_OP || format == TWO_OP_2 || -+ format == DEST || format == DEST_2)); -+ dest_address = unaligned_get_address(thread, -+ ((inst >> 16) & 0x7ff), -+ four_byte, save_an, -+ save_dn, &write_back_an); -+ } -+ -+ if (write_back_an) { -+ /* -+ * restore any modified An registers -+ */ -+ asm volatile ( -+ " move.4 CSR, %0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " move.4 a0, (%1) \n\t" -+ " move.4 a1, 4(%1) \n\t" -+ " move.4 a2, 8(%1) \n\t" -+ " move.4 a3, 12(%1) \n\t" -+ " move.4 a4, 16(%1) \n\t" -+ " move.4 a5, 20(%1) \n\t" -+ " move.4 a6, 24(%1) \n\t" -+ " move.4 a7, 28(%1) \n\t" -+ " setcsr #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ : -+ : "d" ((1 << 14) | (thread << 15)), "a" (save_an) -+ : "cc" -+ ); -+ } -+ -+ /* -+ * get source 2 register if needed, and modify inst to use d1 for -+ * source-2 source-2 will come from this thread, not the trapping thread -+ */ -+ source2 = 0; -+ if ((op >= 8 && op <= 0x17) || -+ ((op == 2 || op == 6) && (inst & 0x4000000))) { -+ int src_dn = (inst >> 11) & 0xf; -+ source2 = save_dn[src_dn]; -+ /* -+ * force the emulated instruction to use d1 for source2 operand -+ */ -+ emulate_inst = (emulate_inst & 0xffff07ff) | 0x800; -+ } -+ -+ if (likely(op != MOVEI)) { -+ /* -+ * change emulated instruction source1 to d0 -+ */ -+ emulate_inst &= ~0x7ff; -+ emulate_inst |= 1 << 8; -+ } -+ -+ if (unlikely(op == 6 || op == 2)) { -+ /* -+ * Set destination to d0 -+ */ -+ emulate_inst &= ~(0xf << 16); -+ } else if (likely(op != CMPI)) { -+ /* -+ * Set general destination field to d0. -+ */ -+ emulate_inst &= ~(0x7ff << 16); -+ emulate_inst |= 1 << 24; -+ } -+ -+ /* -+ * execute emulated instruction d0, to d0, no memory access -+ * source2 if needed will be in d1 -+ * source3, CSR, and accumulators are set up before execution -+ */ -+ *((unsigned int *)&trap_emulate) = emulate_inst; -+ flush_dcache_range((unsigned long)(&trap_emulate), -+ (unsigned long)(&trap_emulate) + 4); -+ -+ result = ubicom32_emulate_insn(source1, source2, source3, -+ save_acc, &save_csr); -+ -+ /* -+ * set the result value -+ */ -+ if (dest_operand) { -+ /* -+ * copy result to memory -+ */ -+ if (four_byte) { -+ *dest_address++ = -+ (unsigned char)((result >> 24) & 0xff); -+ *dest_address++ = -+ (unsigned char)((result >> 16) & 0xff); -+ } -+ *dest_address++ = (unsigned char)((result >> 8) & 0xff); -+ *dest_address = (unsigned char)(result & 0xff); -+ } else if (likely(op != CMPI)) { -+ /* -+ * copy result to a register, using move.4 dest, result -+ */ -+ extern unsigned int unaligned_trap_set_result; -+ *((unsigned int *)&unaligned_trap_set_result) &= ~0x7ff0000; -+ -+ if (op == 2 || op == 6) { -+ *((unsigned int *)&unaligned_trap_set_result) |= -+ ((inst & 0x000f0000) | 0x01000000); -+ } else { -+ *((unsigned int *)&unaligned_trap_set_result) |= -+ (inst & 0x7ff0000); -+ } -+ flush_dcache_range((unsigned long)&unaligned_trap_set_result, -+ ((unsigned long)(&unaligned_trap_set_result) + 4)); -+ -+ asm volatile ( -+ /* result uses thread's registers */ -+ " move.4 CSR, %1 \n\t" -+ " setcsr_flush 0 \n\t" -+ "unaligned_trap_set_result: \n\t" -+ " move.4 #0, %0 \n\t" -+ " setcsr #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ : -+ : "d"(result), "d" ((1 << 14) | (thread << 15)) -+ : "cc" -+ ); -+ } -+ -+ /* -+ * bump PC in thread and restore implicit register changes -+ */ -+ asm volatile ( -+ " move.4 CSR, %0 \n\t" -+ " setcsr_flush 0 \n\t" -+ " move.4 pc, %1 \n\t" -+ " move.4 acc0_lo, (%3) \n\t" -+ " move.4 acc0_hi, 4(%3) \n\t" -+ " move.4 acc1_lo, 8(%3) \n\t" -+ " move.4 acc1_hi, 12(%3) \n\t" -+ " move.4 mac_rc16, 16(%3) \n\t" -+ " move.4 CSR, %2 \n\t" -+ " setcsr #0 \n\t" -+ " setcsr_flush 0 \n\t" -+ : -+ : "d"((1 << 14) | (thread << 15)), -+ "d"(pc + 4), "d"(save_csr), "a"(save_acc) -+ : "cc" -+ ); -+} -+ -+/* -+ * unaligned_only() -+ * Return true if either of the unaligned causes are set (and no others). -+ */ -+int unaligned_only(unsigned int cause) -+{ -+ unsigned int unaligned_cause_mask = -+ (1 << TRAP_CAUSE_DST_MISALIGNED) | -+ (1 << TRAP_CAUSE_SRC1_MISALIGNED); -+ -+ BUG_ON(cause == 0); -+ return (cause & unaligned_cause_mask) == cause; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/kernel/vmlinux.lds.S linux-2.6.30.10-ubi/arch/ubicom32/kernel/vmlinux.lds.S ---- linux-2.6.30.10/arch/ubicom32/kernel/vmlinux.lds.S 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/kernel/vmlinux.lds.S 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,370 @@ -+/* -+ * arch/ubicom32/kernel/vmlinux.lds.S -+ * vmlinux primary linker script -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * Sanity checks to prevent errors later on that are much harder to understand -+ */ -+#if !defined APP_OCM_CODE_SIZE -+#error APP_OCM_CODE_SIZE has not been defined in ocm_size.h -+#endif -+ -+#if !defined APP_OCM_DATA_SIZE -+#error APP_OCM_DATA_SIZE has not been defined in ocm_size.h -+#endif -+ -+/* -+ * The `free' ocm area that ultra does not use. -+ */ -+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE -+#define OCM_FREE_START (OCMSTART + APP_OCM_CODE_SIZE) -+#define OCM_FREE_LENGTH (OCMSIZE - APP_OCM_CODE_SIZE - APP_OCM_DATA_SIZE) -+#else -+#define OCM_FREE_START OCMEND -+#define OCM_FREE_LENGTH 0 -+#endif -+ -+/* -+ * If you want to limit OCM use for text/data or completely disable it -+ * you can change these values. -+ */ -+#define OCM_TEXT_LENGTH OCM_FREE_LENGTH -+#define OCM_DATA_LENGTH OCM_FREE_LENGTH -+ -+#define RAM_START KERNELSTART -+#define RAM_LENGTH ((SDRAMSTART + CONFIG_MIN_RAMSIZE) - RAM_START) -+#define TEXT ram -+#define DATA ram -+#define INIT ram -+#define BSS ram -+ -+#ifndef DATA_ADDR -+#define DATA_ADDR -+#endif -+ -+#include -+ -+OUTPUT_ARCH(ubicom32) -+ENTRY(_start) -+ -+MEMORY { -+ ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH -+ syscall : ORIGIN = OS_SYSCALL_BEGIN, LENGTH = (OS_SYSCALL_END - OS_SYSCALL_BEGIN) -+ ocm : ORIGIN = OCM_FREE_START, LENGTH = OCM_FREE_LENGTH -+} -+ -+jiffies = jiffies_64 + 4; -+ -+/* -+ * Fixed locations required by gdb coredumps. -+ * -+ * Note that the names are what gdb is expecting so renaming will break -+ * the toolchain. -+ */ -+__ocm_begin = OCMSTART; -+__ocm_limit = __ocm_begin + OCMSIZE; -+__sdram_begin = SDRAMSTART; -+__sdram_limit = __sdram_begin + CONFIG_MIN_RAMSIZE; -+__filemedia_begin_addr = FLASHSTART; -+__filemedia_end_addr = __filemedia_begin_addr + 0x00800000; -+ -+/* -+ * For internal diagnostics -+ */ -+__os_syscall_begin = OS_SYSCALL_BEGIN; -+__os_syscall_end = OS_SYSCALL_END; -+ -+SECTIONS { -+ -+ .fixed_text : { -+ _begin = .; -+ *(.skip_syscall) -+ *(.old_syscall_entry.text) -+ __fixed_text_end = .; -+ } > TEXT -+ . = _begin + SIZEOF(.fixed_text) ; -+ -+ /* -+ * System call text in lower ocm (fixed location, can never change) -+ */ -+ __syscall_text_load_begin = .; -+ __syscall_text_run_begin = OS_SYSCALL_BEGIN; -+ -+ .syscall_text __syscall_text_run_begin : AT(__syscall_text_load_begin) { -+ *(.syscall_entry.text) /* Must be at OS_SYSCALL_BEGIN 0x3ffc0040 */ -+ *(.kernel_unprotected) -+ . = ALIGN(4); -+ __syscall_text_run_end = .; -+ } > syscall /* .syscall_text */ -+ . = __syscall_text_load_begin + __syscall_text_run_end - __syscall_text_run_begin ; -+ __ocm_text_load_begin = .; -+ __ocm_text_run_begin = OCM_FREE_START ; -+ .ocm_text __ocm_text_run_begin : AT(__ocm_text_load_begin) { -+#if OCM_TEXT_LENGTH -+ *(.ocm_text) -+ *(.sched.text) -+ *(.spinlock.text) -+#include -+ . = ALIGN(4); -+#endif -+ __ocm_text_run_end = .; -+ __data_begin = ALIGN(OCM_SECTOR_SIZE); -+ } > ocm /* .ocm_text */ -+ -+ .ocm_module_text __ocm_text_run_end (NOLOAD) : AT(__ocm_text_run_end) { -+ __ocm_inst_heap_begin = .; -+ /* Reserve the min requested */ -+ . += (CONFIG_OCM_MODULES_RESERVATION) * 1024; -+#ifdef CONFIG_OCM_MODULES_MAY_CONSUME_REMAINING_CODESPACE -+ /* Round up to OCM sector size (we cannot use it for data) */ -+ . = ALIGN(OCM_SECTOR_SIZE); -+#endif -+ __ocm_inst_heap_end = .; -+ /* update __data_begin */ -+ __data_begin = ALIGN(OCM_SECTOR_SIZE); -+ } > ocm /* .ocm_module_text */ -+ -+ . = __ocm_text_load_begin + __ocm_text_run_end - __ocm_text_run_begin ; -+ __ocm_text_load_end = .; -+ -+ __ocm_data_load_begin = .; -+ __ocm_data_run_begin = __data_begin ; -+#if OCM_DATA_LENGTH -+ .ocm_data __ocm_data_run_begin : AT(__ocm_data_load_begin) { -+#if defined(CONFIG_IRQSTACKS_USEOCM) -+ percpu_irq_stacks = .; -+ . += NR_CPUS * THREAD_SIZE; -+#endif -+ *(.ocm_data) -+ . = ALIGN(4) ; -+ __ocm_data_run_end = .; -+ } > ocm -+ . = __ocm_data_load_begin + __ocm_data_run_end - __ocm_data_run_begin ; -+#else -+ __ocm_data_run_end = __ocm_data_run_begin; -+#endif -+ __ocm_data_load_end = .; -+ -+ __ocm_free_begin = __ocm_data_run_end; -+ __ocm_free_end = OCM_FREE_START + OCM_FREE_LENGTH; -+ -+ .text __ocm_data_load_end : AT(__ocm_data_load_end) { -+ . = ALIGN(4); -+ _stext = .; -+ _text = .; -+ TEXT_TEXT -+ SCHED_TEXT -+ LOCK_TEXT -+ *(.text.lock) -+ *(.text.__libgcc_udivmodsi) -+ *(.text.__libgcc_divmodsi) -+ *(.text.__libgcc_muldi3) -+ *(.text.__libgcc_udivmoddi) -+ *(.text.__libgcc_divmoddi) -+ *(.text.*) -+#if OCM_TEXT_LENGTH == 0 -+ *(.ocm_text) -+ *(.sched.text) -+ *(.spinlock.text) -+#endif -+ . = ALIGN(16); /* Exception table */ -+ __start___ex_table = .; -+ *(__ex_table) -+ __stop___ex_table = .; -+ -+ *(.rodata) *(.rodata.*) -+ *(__vermagic) /* Kernel version magic */ -+ *(__markers_strings) -+ *(.rodata1) -+ *(.rodata.str1.1) -+ *(__tracepoints_strings) -+ -+ /* PCI quirks */ -+ __start_pci_fixups_early = . ; -+ *(.pci_fixup_early) -+ __end_pci_fixups_early = . ; -+ __start_pci_fixups_header = . ; -+ *(.pci_fixup_header) -+ __end_pci_fixups_header = . ; -+ __start_pci_fixups_final = . ; -+ *(.pci_fixup_final) -+ __end_pci_fixups_final = . ; -+ __start_pci_fixups_enable = . ; -+ *(.pci_fixup_enable) -+ __end_pci_fixups_enable = . ; -+ __start_pci_fixups_resume = . ; -+ *(.pci_fixup_resume) -+ __end_pci_fixups_resume = . ; -+ __start_pci_fixups_resume_early = . ; -+ *(.pci_fixup_resume_early) -+ __end_pci_fixups_resume_early = . ; -+ __start_pci_fixups_suspend = . ; -+ *(.pci_fixup_suspend) -+ __end_pci_fixups_suspend = . ; -+ -+ __start_builtin_fw = . ; -+ *(.builtin_fw) -+ __end_builtin_fw = . ; -+ -+ -+ /* Kernel symbol table: Normal symbols */ -+ . = ALIGN(4); -+ __start___ksymtab = .; -+ *(__ksymtab) -+ __stop___ksymtab = .; -+ -+ /* Kernel symbol table: GPL-only symbols */ -+ __start___ksymtab_gpl = .; -+ *(__ksymtab_gpl) -+ __stop___ksymtab_gpl = .; -+ -+ /* Kernel symbol table: Normal unused symbols */ -+ __start___ksymtab_unused = .; -+ *(__ksymtab_unused) -+ __stop___ksymtab_unused = .; -+ -+ /* Kernel symbol table: GPL-only unused symbols */ -+ __start___ksymtab_unused_gpl = .; -+ *(__ksymtab_unused_gpl) -+ __stop___ksymtab_unused_gpl = .; -+ -+ /* Kernel symbol table: GPL-future symbols */ -+ __start___ksymtab_gpl_future = .; -+ *(__ksymtab_gpl_future) -+ __stop___ksymtab_gpl_future = .; -+ -+ /* Kernel symbol table: Normal symbols */ -+ __start___kcrctab = .; -+ *(__kcrctab) -+ __stop___kcrctab = .; -+ -+ /* Kernel symbol table: GPL-only symbols */ -+ __start___kcrctab_gpl = .; -+ *(__kcrctab_gpl) -+ __stop___kcrctab_gpl = .; -+ -+ /* Kernel symbol table: GPL-future symbols */ -+ __start___kcrctab_gpl_future = .; -+ *(__kcrctab_gpl_future) -+ __stop___kcrctab_gpl_future = .; -+ -+ /* Kernel symbol table: strings */ -+ *(__ksymtab_strings) -+ -+ /* Built-in module parameters */ -+ . = ALIGN(4) ; -+ __start___param = .; -+ *(__param) -+ __stop___param = .; -+ -+ . = ALIGN(4) ; -+ _etext = . ; -+ } > TEXT -+ -+ .data DATA_ADDR : { -+ . = ALIGN(4); -+ _sdata = . ; -+ DATA_DATA -+#if OCM_DATA_LENGTH == 0 -+ *(.ocm_data) -+#endif -+ . = ALIGN(8192) ; -+ _data_protection_end = .; -+ *(.data.init_task) -+ . = ALIGN(4); -+ _edata = . ; -+ } > DATA -+ -+ .init : { -+ . = ALIGN(4096); -+ __init_begin = .; -+ _sinittext = .; -+ INIT_TEXT -+ _einittext = .; -+ *(.init.rodata) -+ INIT_DATA -+ . = ALIGN(16); -+ __setup_start = .; -+ *(.init.setup) -+ __setup_end = .; -+ __initcall_start = .; -+ INITCALLS -+ __initcall_end = .; -+ __con_initcall_start = .; -+ *(.con_initcall.init) -+ __con_initcall_end = .; -+ ___security_initcall_start = .; -+ *(.security_initcall.init) -+ ___security_initcall_end = .; -+#ifdef CONFIG_BLK_DEV_INITRD -+ . = ALIGN(4); -+ __initramfs_start = .; -+ *(.init.ramfs) -+ __initramfs_end = .; -+#endif -+ . = ALIGN(4096); -+ __per_cpu_start = .; -+ *(.data.percpu) -+ *(.data.percpu.shared_aligned) -+ __per_cpu_end = .; -+ -+ . = ALIGN(4096); -+ __init_end = .; -+ } > INIT -+ -+ .eh_frame : -+ { -+ PROVIDE (___eh_frame_begin = .); -+ *(.eh_frame) -+ LONG (0); -+ PROVIDE (___eh_frame_end = .); -+ } > INIT -+ -+ /DISCARD/ : { -+ EXIT_TEXT -+ EXIT_DATA -+ *(.exitcall.exit) -+ } -+ -+ .bss : { -+ . = ALIGN(4); -+ _sbss = . ; -+ *(.bss) -+ *(COMMON) -+ . = ALIGN(4) ; -+ _ebss = . ; -+ _end = . ; -+ } > BSS -+ -+ NOTES > BSS -+ -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/lib/checksum.c linux-2.6.30.10-ubi/arch/ubicom32/lib/checksum.c ---- linux-2.6.30.10/arch/ubicom32/lib/checksum.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/lib/checksum.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,250 @@ -+/* -+ * arch/ubicom32/lib/checksum.c -+ * Optimized checksum utilities for IP. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+/* -+ * INET An implementation of the TCP/IP protocol suite for the LINUX -+ * operating system. INET is implemented using the BSD Socket -+ * interface as the means of communication with the user level. -+ * -+ * IP/TCP/UDP checksumming routines -+ * -+ * Authors: Jorge Cwik, -+ * Arnt Gulbrandsen, -+ * Tom May, -+ * Andreas Schwab, -+ * Lots of code moved from tcp.c and ip.c; see those files -+ * for more names. -+ * -+ * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: -+ * Fixed some nasty bugs, causing some horrible crashes. -+ * A: At some points, the sum (%0) was used as -+ * length-counter instead of the length counter -+ * (%1). Thanks to Roman Hodek for pointing this out. -+ * B: GCC seems to mess up if one uses too many -+ * data-registers to hold input values and one tries to -+ * specify d0 and d1 as scratch registers. Letting gcc choose these -+ * registers itself solves the problem. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access kills, so most -+ of the assembly has to go. */ -+ -+#include -+#include -+ -+static unsigned long do_csum(const unsigned char * buff, int len) -+{ -+ int count; -+ unsigned long result = 0; -+ -+ /* -+ * The following optimized assembly code cannot handle data length less than 7 bytes! -+ */ -+ if (likely(len >= 7)) { -+ len -= (4 - (int)buff) & 3; -+ count = len >> 2; -+ asm ( -+ " sub.4 d15, #0, %2 \n\t" // set up for jump table -+ " and.4 d15, #(32-1), d15 \n\t" // d15 = (-m) & (32 - 1) -+ -+ " bfextu d14, %0, #2 \n\t" // test 2 LSB of buff -+ " jmpne.w.f 100f \n\t" -+ " add.4 %1, #0, %1 \n\t" // clear C -+ " moveai a3, #%%hi(1f) \n\t" // table jump -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.4 a3, (a3,d15) \n\t" -+ " calli a3, 0(a3) \n\t" -+ -+ "100: sub.4 %0, %0, d14 \n\t" -+ " sub.4 d14, #4, d14 \n\t" -+ " lsl.4 d14, d14, #3 \n\t" -+ " add.4 %1, #0, %1 \n\t" // clear C -+ " moveai a3, #%%hi(1f) \n\t" // table jump -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.4 a3, (a3,d15) \n\t" -+ " bfextu %1, (%0)4++, d14 \n\t" // read first partial word -+ " calli a3, 0(a3) \n\t" -+#if 1 -+ "200: lsl.4 %3, %3, #3 \n\t" -+ " bfrvrs d15, (%0), #0 \n\t" // read last word (partial) -+ " bfextu d15, d15, %3 \n\t" -+ " bfrvrs d15, d15, #0 \n\t" -+ " add.4 %1, d15, %1 \n\t" -+ " addc %1, #0, %1 \n\t" // sample C again -+ " jmpt.w.t 2f \n\t" -+#else -+ "200: move.1 d15, 0(%0) \n\t" -+ " lsl.4 d15, d15, #8 \n\t" -+ " add.4 %1, d15, %1 \n\t" -+ " addc %1, #0, %1 \n\t" // sample C again -+ " add.4 %3, #-1, %3 \n\t" -+ " jmpeq.w.t 2f \n\t" -+ -+ " move.1 d15, 1(%0) \n\t" -+ " add.4 %1, d15, %1 \n\t" -+ " addc %1, #0, %1 \n\t" // sample C again -+ " add.4 %3, #-1, %3 \n\t" -+ " jmpeq.w.t 2f \n\t" -+ -+ " move.1 d15, 2(%0) \n\t" -+ " lsl.4 d15, d15, #8 \n\t" -+ " add.4 %1, d15, %1 \n\t" -+ " addc %1, #0, %1 \n\t" // sample C again -+ " jmpt.w.t 2f \n\t" -+#endif -+#if defined(IP7000) || defined(IP7000_REV2) -+ "300: swapb.2 %1, %1 \n\t" -+#else -+ "300: shmrg.2 %1, %1, %1 \n\t" -+ " lsr.4 %1, %1, #8 \n\t" -+ " bfextu %1, %1, #16 \n\t" -+#endif -+ " jmpt.w.t 3f \n\t" -+ -+ "1: add.4 %1, (%0)4++, %1 \n\t" // first add without C -+ " .rept 31 \n\t" -+ " addc %1, (%0)4++, %1 \n\t" -+ " .endr \n\t" -+ " addc %1, #0, %1 \n\t" // sample C again -+ " add.4 %2, #-32, %2 \n\t" -+ " jmpgt.w.t 1b \n\t" -+ -+ " and.4 %3, #3, %3 \n\t" // check n -+ " jmpne.w.f 200b \n\t" -+ -+ "2: .rept 2 \n\t" -+ " lsr.4 d15, %1, #16 \n\t" -+ " bfextu %1, %1, #16 \n\t" -+ " add.4 %1, d15, %1 \n\t" -+ " .endr \n\t" -+ " btst d14, #3 \n\t" // start from odd address (<< 3)? -+ " jmpne.w.f 300b \n\t" -+ "3: \n\t" -+ -+ : "+a"(buff), "+d"(result), "+d"(count), "+d"(len) -+ : -+ : "d15", "d14", "a3", "cc" -+ ); -+ -+ return result; -+ } -+ -+ /* -+ * handle a few bytes and fold result into 16-bit -+ */ -+ while (len-- > 0) { -+ result += (*buff++ << 8); -+ if (len) { -+ result += *buff++; -+ len--; -+ } -+ } -+ asm ( -+ " .rept 2 \n\t" -+ " lsr.4 d15, %0, #16 \n\t" -+ " bfextu %0, %0, #16 \n\t" -+ " add.4 %0, d15, %0 \n\t" -+ " .endr \n\t" -+ : "+d" (result) -+ : -+ : "d15", "cc" -+ ); -+ -+ return result; -+} -+ -+/* -+ * This is a version of ip_compute_csum() optimized for IP headers, -+ * which always checksum on 4 octet boundaries. -+ */ -+__sum16 ip_fast_csum(const void *iph, unsigned int ihl) -+{ -+ return (__force __sum16)~do_csum(iph,ihl*4); -+} -+ -+/* -+ * computes the checksum of a memory block at buff, length len, -+ * and adds in "sum" (32-bit) -+ * -+ * returns a 32-bit number suitable for feeding into itself -+ * or csum_tcpudp_magic -+ * -+ * this function must be called with even lengths, except -+ * for the last fragment, which may be odd -+ * -+ * it's best to have buff aligned on a 32-bit boundary -+ */ -+__wsum csum_partial(const void *buff, int len, __wsum sum) -+{ -+ unsigned int result = do_csum(buff, len); -+ -+ /* add in old sum, and carry.. */ -+ result += (__force u32)sum; -+ if ((__force u32)sum > result) -+ result += 1; -+ return (__force __wsum)result; -+} -+ -+EXPORT_SYMBOL(csum_partial); -+ -+/* -+ * this routine is used for miscellaneous IP-like checksums, mainly -+ * in icmp.c -+ */ -+__sum16 ip_compute_csum(const void *buff, int len) -+{ -+ return (__force __sum16)~do_csum(buff,len); -+} -+ -+/* -+ * copy from fs while checksumming, otherwise like csum_partial -+ */ -+ -+__wsum -+csum_partial_copy_from_user(const void __user *src, void *dst, -+ int len, __wsum sum, int *csum_err) -+{ -+ if (csum_err) *csum_err = 0; -+ memcpy(dst, (__force const void *)src, len); -+ return csum_partial(dst, len, sum); -+} -+ -+/* -+ * copy from ds while checksumming, otherwise like csum_partial -+ */ -+ -+__wsum -+csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) -+{ -+ memcpy(dst, src, len); -+ return csum_partial(dst, len, sum); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/lib/delay.c linux-2.6.30.10-ubi/arch/ubicom32/lib/delay.c ---- linux-2.6.30.10/arch/ubicom32/lib/delay.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/lib/delay.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,49 @@ -+/* -+ * arch/ubicom32/lib/delay.c -+ * Ubicom32 implementation of udelay() -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * read_current_timer() -+ * Return the current value of sysval. -+ */ -+int __devinit read_current_timer(unsigned long *timer_val) -+{ -+ *timer_val = (long)(UBICOM32_IO_TIMER->sysval); -+ return 0; -+} -+ -+ -+void udelay(unsigned long usecs) -+{ -+ _udelay(usecs); -+} -+EXPORT_SYMBOL(udelay); -diff -ruN linux-2.6.30.10/arch/ubicom32/lib/Makefile linux-2.6.30.10-ubi/arch/ubicom32/lib/Makefile ---- linux-2.6.30.10/arch/ubicom32/lib/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/lib/Makefile 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,32 @@ -+# -+# arch/ubicom32/lib/Makefile -+# -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+# -+# Makefile for m68knommu specific library files.. -+# -+ -+lib-y := checksum.o delay.o mem_ubicom32.o -diff -ruN linux-2.6.30.10/arch/ubicom32/lib/mem_ubicom32.c linux-2.6.30.10-ubi/arch/ubicom32/lib/mem_ubicom32.c ---- linux-2.6.30.10/arch/ubicom32/lib/mem_ubicom32.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/lib/mem_ubicom32.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,343 @@ -+/* -+ * arch/ubicom32/lib/mem_ubicom32.c -+ * String functions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+ -+#define LIKELY likely -+#define UNLIKELY unlikely -+ -+typedef u32_t addr_t; -+ -+/* -+ * memcpy() -+ */ -+void *memcpy(void *dest, const void *src, size_t n) -+{ -+ void *dest_ret = dest; -+ -+ if (LIKELY((((addr_t)dest ^ (addr_t)src) & 3) == 0) && LIKELY(n > 6)) { -+ size_t m; -+ n -= (4 - (addr_t)dest) & 0x03; -+ m = n >> 2; -+ asm volatile ( -+ " sub.4 d15, #0, %2 \n\t" // set up for jump table -+ " and.4 d15, #(32-1), d15 \n\t" // d15 = (-m) & (32 - 1) -+ " moveai a3, #%%hi(1f) \n\t" -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.4 a3, (a3,d15) \n\t" -+ -+ " bfextu d15, %0, #2 \n\t" // d15 = (dest & 3) -+ " jmpne.w.f 100f \n\t" -+ " calli a3, 0(a3) \n\t" // 4-byte alignment -+ -+ "100: cmpi d15, #2 \n\t" -+ " jmpne.s.f 101f \n\t" -+ " move.2 (%0)2++, (%1)2++ \n\t" -+ " calli a3, 0(a3) \n\t" // 2-byte alignment -+ -+ "101: move.1 (%0)1++, (%1)1++ \n\t" -+ " jmpgt.s.f 102f \n\t" // 3-byte alignment -+ " move.2 (%0)2++, (%1)2++ \n\t" // 1-byte alignment -+ "102: calli a3, 0(a3) \n\t" -+ -+ "200: cmpi %3, #2 \n\t" -+ " jmplt.s.f 201f \n\t" -+ " move.2 (%0)2++, (%1)2++ \n\t" -+ " jmpeq.s.t 2f \n\t" -+ "201: move.1 (%0)1++, (%1)1++ \n\t" -+ " jmpt.w.t 2f \n\t" -+ -+ "1: .rept 25 \n\t" -+ " movea (%0)4++, (%1)4++ \n\t" -+ " .endr \n\t" -+ " .rept 7 \n\t" -+ " move.4 (%0)4++, (%1)4++ \n\t" -+ " .endr \n\t" -+ " add.4 %2, #-32, %2 \n\t" -+ " jmpgt.w.f 1b \n\t" -+ -+ " and.4 %3, #3, %3 \n\t" // check n -+ " jmpne.w.f 200b \n\t" -+ "2: \n\t" -+ : "+a" (dest), "+a" (src), "+d" (m), "+d" (n) -+ : -+ : "d15", "a3", "memory", "cc" -+ ); -+ -+ return dest_ret; -+ } -+ -+ if (LIKELY((((addr_t)dest ^ (addr_t)src) & 1) == 0) && LIKELY(n > 2)) { -+ size_t m; -+ n -= (addr_t)dest & 0x01; -+ m = n >> 1; -+ asm volatile ( -+ " sub.4 d15, #0, %2 \n\t" // set up for jump table -+ " and.4 d15, #(32-1), d15 \n\t" // d15 = (-m) & (32 - 1) -+ " moveai a3, #%%hi(1f) \n\t" -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.4 a3, (a3,d15) \n\t" -+ -+ " btst %0, #0 \n\t" // check bit 0 -+ " jmpne.w.f 100f \n\t" -+ " calli a3, 0(a3) \n\t" // 4-byte alignment -+ -+ "100: move.1 (%0)1++, (%1)1++ \n\t" -+ " calli a3, 0(a3) \n\t" -+ -+ "200: move.1 (%0)1++, (%1)1++ \n\t" -+ " jmpt.w.t 2f \n\t" -+ -+ "1: .rept 32 \n\t" -+ " move.2 (%0)2++, (%1)2++ \n\t" -+ " .endr \n\t" -+ " add.4 %2, #-32, %2 \n\t" -+ " jmpgt.w.f 1b \n\t" -+ -+ " and.4 %3, #1, %3 \n\t" // check n -+ " jmpne.w.f 200b \n\t" -+ "2: \n\t" -+ -+ : "+a" (dest), "+a" (src), "+d" (m), "+d" (n) -+ : -+ : "d15", "a3", "memory", "cc" -+ ); -+ -+ return dest_ret; -+ } -+ -+ asm volatile ( -+ " sub.4 d15, #0, %2 \n\t" -+ " jmpeq.w.f 2f \n\t" -+ " and.4 d15, #(16-1), d15 \n\t" // d15 = (-n) & (16 - 1) -+ " moveai a3, #%%hi(1f) \n\t" -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.4 a3, (a3,d15) \n\t" -+ " calli a3, 0(a3) \n\t" -+ -+ "1: .rept 16 \n\t" -+ " move.1 (%0)1++, (%1)1++ \n\t" -+ " .endr \n\t" -+ " add.4 %2, #-16, %2 \n\t" -+ " jmpgt.w.f 1b \n\t" -+ "2: \n\t" -+ -+ : "+a" (dest), "+a" (src), "+d" (n) -+ : -+ : "d15", "a3", "memory", "cc" -+ ); -+ -+ return dest_ret; -+} -+ -+/* -+ * memset() -+ */ -+void *memset(void *s, int c, size_t n) -+{ -+ void *s_ret = s; -+ -+ if (LIKELY(n > 6)) { -+ size_t m; -+ n -= (4 - (addr_t)s) & 0x03; -+ m = n >> 2; -+ asm volatile ( -+ " sub.4 d15, #0, %2 \n\t" // set up for jump table -+ " and.4 d15, #(32-1), d15 \n\t" // d15 = (-m) & (32 - 1) -+ " shmrg.1 %1, %1, %1 \n\t" -+ " shmrg.2 %1, %1, %1 \n\t" // %1 = (c<<24)|(c<<16)|(c<<8)|c -+ " moveai a3, #%%hi(1f) \n\t" -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.4 a3, (a3,d15) \n\t" -+ -+ " bfextu d15, %0, #2 \n\t" // d15 = (s & 3) -+ " jmpne.w.f 100f \n\t" -+ " calli a3, 0(a3) \n\t" // 4-byte alignment -+ -+ "100: cmpi d15, #2 \n\t" -+ " jmpne.s.f 101f \n\t" -+ " move.2 (%0)2++, %1 \n\t" -+ " calli a3, 0(a3) \n\t" // 2-byte alignment -+ -+ "101: move.1 (%0)1++, %1 \n\t" -+ " jmpgt.s.f 102f \n\t" // 3-byte alignment -+ " move.2 (%0)2++, %1 \n\t" // 1-byte alignment -+ "102: calli a3, 0(a3) \n\t" -+ -+ "200: cmpi %3, #2 \n\t" -+ " jmplt.s.f 201f \n\t" -+ " move.2 (%0)2++, %1 \n\t" -+ " jmpeq.s.t 2f \n\t" -+ "201: move.1 (%0)1++, %1 \n\t" -+ " jmpt.w.t 2f \n\t" -+ -+ "1: .rept 25 \n\t" -+ " movea (%0)4++, %1 \n\t" -+ " .endr \n\t" -+ " .rept 7 \n\t" -+ " move.4 (%0)4++, %1 \n\t" -+ " .endr \n\t" -+ " add.4 %2, #-32, %2 \n\t" -+ " jmpgt.w.f 1b \n\t" -+ -+ " and.4 %3, #3, %3 \n\t" // test bit 1 of n -+ " jmpne.w.f 200b \n\t" -+ "2: \n\t" -+ -+ : "+a" (s), "+d" (c), "+d" (m), "+d" (n) -+ : -+ : "d15", "a3", "memory", "cc" -+ ); -+ -+ return s_ret; -+ } -+ -+ asm volatile ( -+ " sub.4 d15, #0, %2 \n\t" -+ " jmpeq.w.f 2f \n\t" -+ " and.4 d15, #(8-1), d15 \n\t" // d15 = (-%2) & (16 - 1) -+ " moveai a3, #%%hi(1f) \n\t" -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.4 a3, (a3,d15) \n\t" -+ " calli a3, 0(a3) \n\t" -+ -+ "1: .rept 8 \n\t" -+ " move.1 (%0)1++, %1 \n\t" -+ " .endr \n\t" -+ "2: \n\t" -+ -+ : "+a" (s), "+d" (c), "+d" (n) -+ : -+ : "d15", "a3", "memory", "cc" -+ ); -+ -+ return s_ret; -+} -+ -+void *memmove(void *dest, const void *src, size_t n) -+{ -+ char *tmp; -+ const char *s; -+ -+ if (n == 0) -+ return dest; -+ -+ tmp = dest; -+ s = src; -+ -+ /* -+ * Will perform 16-bit move if possible -+ */ -+ if (likely((((u32)dest | (u32)src | n) & 1) == 0)) { -+ if (dest <= src) { -+ asm volatile ( -+ " sub.4 d15, #0, %2 \n\t" // set up for jump table -+ " and.4 d15, #(32-2), d15 \n\t" // d15 = (- count) & (32 - 2) -+ " moveai a3, #%%hi(1f) \n\t" -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.2 a3, (a3,d15) \n\t" -+ " calli a3, 0(a3) \n\t" -+ -+ "1: .rept 16 \n\t" -+ " move.2 (%0)2++, (%1)2++ \n\t" -+ " .endr \n\t" -+ " add.4 %2, #-32, %2 \n\t" -+ " jmpgt.w.f 1b \n\t" -+ -+ : "+a" (tmp), "+a" (s), "+d" (n) -+ : -+ : "d15", "a3", "memory", "cc" -+ ); -+ } else { -+ tmp += n; -+ s += n; -+ asm volatile ( -+ " sub.4 d15, #0, %2 \n\t" // set up for jump table -+ " and.4 d15, #(32-2), d15 \n\t" // d15 = (- count) & (32 - 2) -+ " moveai a3, #%%hi(1f) \n\t" -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.2 a3, (a3,d15) \n\t" -+ " calli a3, 0(a3) \n\t" -+ -+ "1: .rept 16 \n\t" -+ " move.2 -2(%0)++, -2(%1)++ \n\t" -+ " .endr \n\t" -+ " add.4 %2, #-32, %2 \n\t" -+ " jmpgt.w.f 1b \n\t" -+ -+ : "+a" (tmp), "+a" (s), "+d" (n) -+ : -+ : "d15", "a3", "memory", "cc" -+ ); -+ } -+ return dest; -+ } -+ -+ if (dest <= src) { -+ asm volatile ( -+ " sub.4 d15, #0, %2 \n\t" // set up for jump table -+ " and.4 d15, #(16-1), d15 \n\t" // d15 = (- count) & (16 - 1) -+ " moveai a3, #%%hi(1f) \n\t" -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.4 a3, (a3,d15) \n\t" -+ " calli a3, 0(a3) \n\t" -+ -+ "1: .rept 16 \n\t" -+ " move.1 (%0)1++, (%1)1++ \n\t" -+ " .endr \n\t" -+ " add.4 %2, #-16, %2 \n\t" -+ " jmpgt.w.f 1b \n\t" -+ : "+a" (tmp), "+a" (s), "+d" (n) -+ : -+ : "d15", "a3", "memory", "cc" -+ ); -+ } else { -+ tmp += n; -+ s += n; -+ asm volatile ( -+ " sub.4 d15, #0, %2 \n\t" // set up for jump table -+ " and.4 d15, #(16-1), d15 \n\t" // d15 = (- count) & (16 - 1) -+ " moveai a3, #%%hi(1f) \n\t" -+ " lea.1 a3, %%lo(1f)(a3) \n\t" -+ " lea.4 a3, (a3,d15) \n\t" -+ " calli a3, 0(a3) \n\t" -+ -+ "1: .rept 16 \n\t" -+ " move.1 -1(%0)++, -1(%1)++ \n\t" -+ " .endr \n\t" -+ " add.4 %2, #-16, %2 \n\t" -+ " jmpgt.w.f 1b \n\t" -+ : "+a" (tmp), "+a" (s), "+d" (n) -+ : -+ : "d15", "a3", "memory", "cc" -+ ); -+ } -+ return dest; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/audio.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/audio.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/audio.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/audio.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,134 @@ -+/* -+ * arch/ubicom32/mach-common/audio.c -+ * Generic initialization for Ubicom32 Audio -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* -+ * The number of audio devices currently allocated, used for .id -+ */ -+static int __initdata audio_device_count; -+ -+/* -+ * The maximum number of resources (cards) that the audio will have. -+ * Currently 3, a register space, and up to 2 interrupts. -+ */ -+#define AUDIO_MAX_RESOURCES 3 -+ -+/* -+ * audio_device_alloc -+ * Checks the device tree and allocates a platform_device if found -+ */ -+struct platform_device * __init audio_device_alloc(const char *driver_name, -+ const char *node_name, const char *inst_name, int priv_bytes) -+{ -+ struct platform_device *pdev; -+ struct resource *res; -+ struct audio_node *audio_node; -+ struct ubi32pcm_platform_data *pdata; -+ struct audio_dev_regs *adr; -+ int idx; -+ -+ /* -+ * Check the device tree for the audio node -+ */ -+ audio_node = (struct audio_node *)devtree_find_node(node_name); -+ if (!audio_node) { -+ printk(KERN_WARNING "audio device '%s' not found\n", node_name); -+ return NULL; -+ } -+ -+ if (audio_node->version != AUDIONODE_VERSION) { -+ printk(KERN_WARNING "audio node not compatible\n"); -+ return NULL; -+ } -+ -+ /* -+ * Find the instance in this node -+ */ -+ adr = audio_node->regs->adr; -+ for (idx = 0; idx < audio_node->regs->max_devs; idx++) { -+ if ((adr->version == AUDIO_DEV_REGS_VERSION) && -+ (strcmp(adr->name, inst_name) == 0)) { -+ break; -+ } -+ adr++; -+ } -+ if (idx == audio_node->regs->max_devs) { -+ printk(KERN_WARNING "audio inst '%s' not found in device '%s'\n", inst_name, node_name); -+ return NULL; -+ } -+ -+ /* -+ * Dynamically create the platform_device structure and resources -+ */ -+ pdev = kzalloc(sizeof(struct platform_device) + -+ sizeof(struct ubi32pcm_platform_data) + -+ priv_bytes , GFP_KERNEL); -+ if (!pdev) { -+ printk(KERN_WARNING "audio could not alloc pdev\n"); -+ return NULL; -+ } -+ -+ res = kzalloc(sizeof(struct resource) * AUDIO_MAX_RESOURCES, -+ GFP_KERNEL); -+ if (!res) { -+ kfree(pdev); -+ printk(KERN_WARNING "audio could not alloc res\n"); -+ return NULL; -+ } -+ -+ pdev->name = driver_name; -+ pdev->id = audio_device_count++; -+ pdev->resource = res; -+ -+ /* -+ * Fill in the resources and platform data from devtree information -+ */ -+ res[0].start = (u32_t)(audio_node->regs); -+ res[0].end = (u32_t)(audio_node->regs); -+ res[0].flags = IORESOURCE_MEM; -+ res[1 + AUDIO_TX_IRQ_RESOURCE].start = audio_node->dn.sendirq; -+ res[1 + AUDIO_TX_IRQ_RESOURCE].flags = IORESOURCE_IRQ; -+ res[1 + AUDIO_RX_IRQ_RESOURCE].start = audio_node->dn.recvirq; -+ res[1 + AUDIO_RX_IRQ_RESOURCE].flags = IORESOURCE_IRQ; -+ pdev->num_resources = 3; -+ -+ printk(KERN_INFO "Audio.%d '%s':'%s' found irq=%d/%d.%d regs=%p pdev=%p/%p\n", -+ pdev->id, node_name, inst_name, audio_node->dn.sendirq, -+ audio_node->dn.recvirq, idx, audio_node->regs, pdev, res); -+ pdata = (struct ubi32pcm_platform_data *)(pdev + 1); -+ pdev->dev.platform_data = pdata; -+ pdata->node_name = node_name; -+ pdata->inst_name = inst_name; -+ pdata->inst_num = idx; -+ if (priv_bytes) { -+ pdata->priv_data = pdata + 1; -+ } -+ -+ return pdev; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/board.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/board.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/board.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/board.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,63 @@ -+/* -+ * arch/ubicom32/mach-common/board.c -+ * Board init and support code. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+ -+struct boardnode { -+ struct devtree_node dn; -+ const char *revision; -+}; -+ -+static const struct boardnode *bn; -+ -+/* -+ * board_get_revision() -+ * Returns revision string of the board. -+ */ -+const char *board_get_revision(void) -+{ -+ if (!bn) { -+ return "NULL"; -+ } -+ -+ return bn->revision; -+} -+ -+/* -+ * board_init -+ */ -+void __init board_init(void) -+{ -+ bn = (struct boardnode *)devtree_find_node("board"); -+ if (!bn) { -+ printk(KERN_WARNING "board node not found\n"); -+ return; -+ } -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/bootargs.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/bootargs.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/bootargs.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/bootargs.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,63 @@ -+/* -+ * arch/ubicom32/mach-common/bootargs.c -+ * Board init and support code. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+ -+struct bootargsnode { -+ struct devtree_node dn; -+ const char cmdline[512]; -+}; -+ -+static const struct bootargsnode *ban; -+ -+/* -+ * bootargs_get_cmdline() -+ * Returns kernel boot arguments set by the bootloader. -+ */ -+const char *bootargs_get_cmdline(void) -+{ -+ if (!ban) { -+ return ""; -+ } -+ -+ return ban->cmdline; -+} -+ -+/* -+ * bootargs_init -+ */ -+void __init bootargs_init(void) -+{ -+ ban = (struct bootargsnode *)devtree_find_node("bootargs"); -+ if (!ban) { -+ printk(KERN_WARNING "bootargs node not found\n"); -+ return; -+ } -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/cachectl.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/cachectl.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/cachectl.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/cachectl.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,136 @@ -+/* -+ * arch/ubicom32/mach-common/cachectl.c -+ * Architecture cache control support -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+ -+/* -+ * The write queue flush procedure in mem_cache_control needs to make -+ * DCACHE_WRITE_QUEUE_LENGTH writes to DDR (not OCM). Here we reserve some -+ * memory for this operation. -+ * Allocate array of cache lines of least DCACHE_WRITE_QUEUE_LENGTH + 1 words in -+ * length rounded up to the nearest cache line. -+ */ -+#define CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE \ -+ ALIGN(sizeof(int) * (DCACHE_WRITE_QUEUE_LENGTH + 1), CACHE_LINE_SIZE) -+ -+static char cache_write_queue_flush_area[CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE] -+ __attribute__((aligned(CACHE_LINE_SIZE))); -+ -+/* -+ * ONE_CCR_ADDR_OP is a helper macro that executes a single CCR operation. -+ */ -+#define ONE_CCR_ADDR_OP(cc, op_addr, op) \ -+ do { \ -+ asm volatile ( \ -+ " btst "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)" \n\t" \ -+ " jmpne.f .-4 \n\t" \ -+ " move.4 "D(CCR_ADDR)"(%0), %1 \n\t" \ -+ " move.1 "D(CCR_CTRL+3)"(%0), %2 \n\t" \ -+ " bset "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)" \n\t" \ -+ " cycles 2 \n\t" \ -+ " btst "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_DONE)" \n\t" \ -+ " jmpeq.f .-4 \n\t" \ -+ : \ -+ : "a"(cc), "r"(op_addr), "r"(op & 0xff) \ -+ : "cc" \ -+ ); \ -+ } while (0) -+ -+/* -+ * mem_cache_control() -+ * Special cache control operation -+ */ -+void mem_cache_control(unsigned long cc, unsigned long begin_addr, -+ unsigned long end_addr, unsigned long op) -+{ -+ unsigned long op_addr; -+ int dccr = cc == DCCR_BASE; -+ if (dccr && op == CCR_CTRL_FLUSH_ADDR) { -+ /* -+ * We ensure all previous writes have left the data cache write -+ * queue by sending DCACHE_WRITE_QUEUE_LENGTH writes (to -+ * different words) down the queue. If this is not done it's -+ * possible that the data we are trying to flush hasn't even -+ * entered the data cache. -+ * The +1 ensure that the final 'flush' is actually a flush. -+ */ -+ int *flush_area = (int *)cache_write_queue_flush_area; -+ asm volatile( -+ " .rept "D(DCACHE_WRITE_QUEUE_LENGTH + 1)" \n\t" -+ " move.4 (%0)4++, d0 \n\t" -+ " .endr \n\t" -+ : "+a"(flush_area) -+ ); -+ } -+ -+ if (dccr) -+ UBICOM32_LOCK(DCCR_LOCK_BIT); -+ else -+ UBICOM32_LOCK(ICCR_LOCK_BIT); -+ -+ /* -+ * Calculate the cache lines we need to operate on that include -+ * begin_addr though end_addr. -+ */ -+ begin_addr = begin_addr & ~(CACHE_LINE_SIZE - 1); -+ end_addr = (end_addr + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1); -+ op_addr = begin_addr; -+ -+ do { -+ ONE_CCR_ADDR_OP(cc, op_addr, op); -+ op_addr += CACHE_LINE_SIZE; -+ } while (likely(op_addr < end_addr)); -+ -+ if (dccr && op == CCR_CTRL_FLUSH_ADDR) { -+ /* -+ * It turns out that when flushing the data cache the last flush -+ * isn't actually complete at this point. This is because there -+ * is another write buffer on the DDR side of the cache that is -+ * arbitrated with the I-Cache. -+ * -+ * The only foolproof method that ensures that the last data -+ * cache flush *actually* completed is to do another flush on a -+ * dirty cache line. This flush will block until the DDR write -+ * buffer is empty. -+ * -+ * Rather than creating a another dirty cache line, we use the -+ * flush_area above as we know that it is dirty from previous -+ * writes. -+ */ -+ ONE_CCR_ADDR_OP(cc, cache_write_queue_flush_area, op); -+ } -+ -+ if (dccr) -+ UBICOM32_UNLOCK(DCCR_LOCK_BIT); -+ else -+ UBICOM32_UNLOCK(ICCR_LOCK_BIT); -+ -+} -+EXPORT_SYMBOL(mem_cache_control); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/common.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/common.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/common.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/common.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,64 @@ -+/* -+ * arch/ubicom32/mach-common/common.c -+ * Common platform support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+/* Minimum CLK support */ -+ -+struct clk *clk_get(struct device *dev, const char *id) -+{ -+ return ERR_PTR(-ENOENT); -+} -+EXPORT_SYMBOL(clk_get); -+ -+void clk_put(struct clk *clk) -+{ -+} -+EXPORT_SYMBOL(clk_put); -+ -+int clk_enable(struct clk *clk) -+{ -+ return 0; -+} -+EXPORT_SYMBOL(clk_enable); -+ -+ -+void clk_disable(struct clk *clk) -+{ -+} -+EXPORT_SYMBOL(clk_disable); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/io.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/io.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/io.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/io.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,250 @@ -+/* -+ * arch/ubicom32/mach-common/io.c -+ * PCI I/O memory read/write support functions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+ -+#ifdef CONFIG_PCI -+unsigned char ioread8(void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ return ubi32_pci_read_u8(addr); -+ else -+ return (unsigned char)(*(volatile unsigned char *)addr); -+} -+EXPORT_SYMBOL(ioread8); -+ -+unsigned short ioread16(void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ return ubi32_pci_read_u16(addr); -+ else -+ return (unsigned short)(*(volatile unsigned short *)addr); -+} -+EXPORT_SYMBOL(ioread16); -+ -+unsigned int ioread32(void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ return ubi32_pci_read_u32(addr); -+ else -+ return (unsigned int)(*(volatile unsigned int *)addr); -+} -+EXPORT_SYMBOL(ioread32); -+ -+void iowrite32(unsigned int val, void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ ubi32_pci_write_u32(val, addr); -+ else -+ *(volatile unsigned int *)addr = val; -+} -+EXPORT_SYMBOL(iowrite32); -+ -+void iowrite16(unsigned short val, void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ ubi32_pci_write_u16(val, addr); -+ else -+ *(volatile unsigned short *)addr = val; -+} -+EXPORT_SYMBOL(iowrite16); -+ -+void iowrite8(unsigned char val, void __iomem *addr) -+{ -+ if (IS_PCI_ADDRESS(addr)) -+ ubi32_pci_write_u8(val, addr); -+ else -+ *(volatile unsigned char *)addr = val; -+} -+EXPORT_SYMBOL(iowrite8); -+ -+void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len) -+{ -+ if (IS_PCI_ADDRESS(from)) { -+ if ((((u32_t)from & 0x3) == 0) && (((u32_t)to & 0x3) == 0)) { -+ while ((int)len >= 4) { -+ *(u32_t *)to = ubi32_pci_read_u32(from); -+ to += 4; -+ from += 4; -+ len -= 4; -+ } -+ } else if ((((u32_t)from & 0x1) == 0) && -+ (((u32_t)to & 0x1) == 0)) { -+ while ((int)len >= 2) { -+ *(u16_t *)to = ubi32_pci_read_u16(from); -+ to += 2; -+ from += 2; -+ len -= 2; -+ } -+ } -+ -+ while (len) { -+ *(u8_t *)to = ubi32_pci_read_u8(from); -+ to++; -+ from++; -+ len--; -+ } -+ } else -+ memcpy(to, (void *)from, len); -+} -+EXPORT_SYMBOL(memcpy_fromio); -+ -+void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len) -+{ -+ if (IS_PCI_ADDRESS(to)) { -+ if ((((u32_t)from & 0x3) == 0) && (((u32_t)to & 0x3) == 0)) { -+ while ((int)len >= 4) { -+ ubi32_pci_write_u32(*(u32_t *)from, to); -+ to += 4; -+ from += 4; -+ len -= 4; -+ } -+ } else if ((((u32_t)from & 0x1) == 0) && -+ (((u32_t)to & 0x1) == 0)) { -+ while ((int)len >= 2) { -+ ubi32_pci_write_u16(*(u16_t *)from, to); -+ to += 2; -+ from += 2; -+ len -= 2; -+ } -+ } -+ -+ while (len) { -+ ubi32_pci_write_u8(*(u8_t *)from, to); -+ from++; -+ to++; -+ len--; -+ } -+ } else -+ memcpy((void *)to, from, len); -+ -+} -+EXPORT_SYMBOL(memcpy_toio); -+ -+void memset_io(volatile void __iomem *addr, int val, size_t len) -+{ -+ if (IS_PCI_ADDRESS(addr)) { -+ while (len) { -+ ubi32_pci_write_u8((unsigned char)val, addr); -+ addr++; -+ len--; -+ } -+ } else -+ memset((void *)addr, val, len); -+ -+} -+EXPORT_SYMBOL(memset_io); -+ -+void ioread8_rep(void __iomem *port, void *buf, unsigned long count) -+{ -+ if (IS_PCI_ADDRESS(port)) { -+ while (count) { -+ *(u8_t *)buf = ioread8(port); -+ buf++; -+ count--; -+ } -+ } else { -+ insb((unsigned int)port, buf, count); -+ } -+ -+} -+EXPORT_SYMBOL(ioread8_rep); -+ -+void ioread16_rep(void __iomem *port, void *buf, unsigned long count) -+{ -+ if (IS_PCI_ADDRESS(port)) { -+ while (count) { -+ *(u16_t *)buf = ioread16(port); -+ buf += 2; -+ count--; -+ } -+ } else { -+ insw((unsigned int)port, buf, count); -+ } -+} -+EXPORT_SYMBOL(ioread16_rep); -+ -+void ioread32_rep(void __iomem *port, void *buf, unsigned long count) -+{ -+ if (IS_PCI_ADDRESS(port)) { -+ while (count) { -+ *(u32_t *)buf = ioread32(port); -+ buf += 4; -+ count--; -+ } -+ } else { -+ insl((unsigned int)port, buf, count); -+ } -+} -+EXPORT_SYMBOL(ioread32_rep); -+ -+void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count) -+{ -+ if (IS_PCI_ADDRESS(port)) { -+ while (count) { -+ iowrite8(*(u8_t *)buf, port); -+ buf++; -+ count--; -+ } -+ } else { -+ outsb((unsigned int)port, buf, count); -+ } -+ -+} -+EXPORT_SYMBOL(iowrite8_rep); -+ -+void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count) -+{ -+ if (IS_PCI_ADDRESS(port)) { -+ while (count) { -+ iowrite16(*(u16_t *)buf, port); -+ buf += 2; -+ count--; -+ } -+ } else { -+ outsw((unsigned int)port, buf, count); -+ } -+} -+EXPORT_SYMBOL(iowrite16_rep); -+ -+void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count) -+{ -+ if (IS_PCI_ADDRESS(port)) { -+ while (count) { -+ iowrite32(*(u32_t *)buf, port); -+ buf += 4; -+ count--; -+ } -+ } else { -+ outsl((unsigned int)port, buf, count); -+ } -+} -+EXPORT_SYMBOL(iowrite32_rep); -+ -+#endif /* CONFIG_PCI */ -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/Kconfig.switch linux-2.6.30.10-ubi/arch/ubicom32/mach-common/Kconfig.switch ---- linux-2.6.30.10/arch/ubicom32/mach-common/Kconfig.switch 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/Kconfig.switch 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,12 @@ -+menuconfig UBICOM_SWITCH -+ tristate "Switch devices" -+ help -+ This option provides Ethernet switch management options via proc fs -+ -+if UBICOM_SWITCH -+config UBICOM_SWITCH_BCM539X -+ tristate "Broadcom BCM539X series (SPI)" -+ depends on SPI_MASTER -+ help -+ Supports Broadcom BCM539X Gigabit Ethernet Switches over SPI -+endif -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/Makefile linux-2.6.30.10-ubi/arch/ubicom32/mach-common/Makefile ---- linux-2.6.30.10/arch/ubicom32/mach-common/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/Makefile 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,41 @@ -+# -+# arch/ubicom32/mach-common/Makefile -+# Makefile for Ubicom32 generic drivers/code. -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+ -+obj-y += cachectl.o common.o usb_tio.o usb.o ubi32-gpio.o board.o bootargs.o profile.o -+obj-$(CONFIG_PCI) += pci.o io.o -+ -+obj-$(CONFIG_FB_UBICOM32) += vdc_tio.o -+obj-$(CONFIG_UBICOM_HID) += ubicom32hid.o -+obj-$(CONFIG_UBICOM_INPUT) += ubicom32input.o -+obj-$(CONFIG_UBICOM_INPUT_I2C) += ubicom32input_i2c.o -+obj-$(CONFIG_UBICOM_SWITCH) += switch-core.o -+obj-$(CONFIG_UBICOM_SWITCH_BCM539X) += switch-bcm539x.o -+obj-$(CONFIG_UIO_UBICOM32RING) += ring_tio.o -+obj-$(CONFIG_SND_UBI32) += audio.o -+obj-$(CONFIG_UBICOM32_PLIO) += plio.o -+ -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/pci.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/pci.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/pci.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/pci.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,1157 @@ -+/* -+ * arch/ubicom32/mach-common/pci.c -+ * PCI interface management. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+static int debug_pci = 1 ; -+ -+/* #define PCI_USE_INTERNAL_LOCK 1 */ -+ -+#ifdef PCI_USE_INTERNAL_LOCK -+#define PCI_LOCK(lock, irqflag) pci_lock_acquire(irqflag) -+#define PCI_UNLOCK(lock, irqflag) pci_lock_release(irqflag) -+#elif defined(CONFIG_SMP) -+static DEFINE_SPINLOCK(pci_master_lock); -+#define PCI_LOCK(lock, irqflag) spin_lock_irqsave(lock, irqflag) -+#define PCI_UNLOCK(lock, irqflag) spin_unlock_irqrestore(lock, irqflag) -+#else -+#define PCI_LOCK(lock, irqflag) local_irq_save(irqflag) -+#define PCI_UNLOCK(lock, irqflag) local_irq_restore(irqflag) -+#endif -+ -+#define PCI_DEV0_IDSEL CONFIG_PCI_DEV0_IDSEL -+#define PCI_DEV1_IDSEL CONFIG_PCI_DEV1_IDSEL -+ -+/* -+ * PCI commands -+ */ -+#define PCI_CMD_INT_ACK 0x00 /* not supported */ -+#define PCI_CMD_SPECIAL 0x01 /* not supported */ -+#define PCI_CMD_IO_READ 0x02 -+#define PCI_CMD_IO_WRITE 0x03 -+#define PCI_CMD_MEM_READ 0x06 -+#define PCI_CMD_MEM_WRITE 0x07 -+#define PCI_CMD_CFG_READ 0x0a -+#define PCI_CMD_CFG_WRITE 0x0b -+#define PCI_CMD_MEM_READ_MULT 0x0c /* not supported */ -+#define PCI_CMD_DUAL_ADDR 0x0d /* not supported */ -+#define PCI_CMD_MEM_READ_LINE 0x0e /* not supported */ -+#define PCI_CMD_MEM_WRITE_INVAL 0x0f /* not supported */ -+/* -+ * Status codes, returned by pci_read_u32() and pci_write_u32() -+ */ -+#define PCI_RESP_IN_PROGRESS 0xff /* request still in queue */ -+#define PCI_RESP_OK 0 -+/* -+ * The following codes indicate that the request has completed -+ */ -+#define PCI_RESP_NO_DEVSEL 1 /* timeout before target asserted -+ * DEVSEL! */ -+#define PCI_RESP_LOST_DEVSEL 2 /* had DEVSEL, but went away before -+ * transfer completed! */ -+#define PCI_RESP_BAD_TRDY 3 /* target asserted TRDY without -+ * DEVSEL! */ -+#define PCI_RESP_NO_TRDY 4 /* timeout before target asserted -+ * TRDY! */ -+#define PCI_RESP_BAD_STOP 5 /* target asserted STOP and TRDY -+ * without DEVSEL! */ -+#define PCI_RESP_TARGET_ABORT 6 -+#define PCI_RESP_TARGET_RETRY 7 -+#define PCI_RESP_TARGET_DISCONNECT 8 -+#define PCI_RESP_MISMATCH 9 /* data read back doesn't match data -+ * written - debug only, the core PCI -+ * routines never return this */ -+#define PCI_RESP_DET_SERR 10 -+#define PCI_RESP_DET_PERR 11 -+#define PCI_RESP_MALFORMED_REQ 12 /* Could be due to misaligned -+ * requests or invalid address */ -+#define PCI_RESP_NO_RESOURCE 13 /* Could be memory or other resourse -+ * like queue space */ -+#define PCI_RESP_ERROR 14 /* All emcompassing error */ -+ -+/* registers in PCI config space */ -+#define PCI_DEVICE_VENDOR_ID_REG 0x00 -+#define PCI_STATUS_COMMAND_REG 0x04 -+#define PCI_CLASS_REVISION_REG 0x08 -+#define PCI_BHLC_REG 0x0c /* BIST, Header type, Latency -+ * timer, Cache line size */ -+#define PCI_BASE_ADDR_REG 0x10 -+#define PCI_BASE_REG_COUNT 6 -+#define CARDBUS_CIS_PTR_REG 0x28 -+#define PCI_SUB_SYSTEM_ID_REG 0x2c -+#define PCI_EXP_ROM_ADDR_REG 0x30 -+#define PCI_CAP_PTR_REG 0x34 -+#define PCI_LGPL_REG 0x3C /* max Latency, min Gnt, interrupt -+ * Pin, interrupt Line */ -+ -+struct pci_master_request { -+ volatile u32_t pci_address; /* must be 4-byte aligned */ -+ volatile u32_t data; /* must be 4-byte aligned */ -+ volatile u8_t cmd; -+ volatile u8_t byte_valid; -+ volatile u8_t status; -+}; -+ -+struct pci_devnode { -+ struct devtree_node dn; -+ u32_t pci_idsel_0; -+ u32_t pci_idsel_1; -+ u32_t pci_cpu_address; -+ struct pci_master_request volatile *volatile req; -+}; -+ -+static struct pci_master_request req; /* globally used for faster master write -+ * (discarding result when possible) */ -+static struct pci_devnode *pci_node; -+ -+#if !defined(CONFIG_DEBUG_PCIMEASURE) -+#define PCI_DECLARE_MEASUREMENT -+#define PCI_MEASUREMENT_START() -+#define PCI_MEASUREMENT_END(idx) -+#else -+#define PCI_DECLARE_MEASUREMENT \ -+ int __diff; \ -+ unsigned int __tstart; -+ -+#define PCI_MEASUREMENT_START() \ -+ __tstart = UBICOM32_IO_TIMER->sysval; -+ -+#define PCI_MEASUREMENT_END(idx) \ -+ __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \ -+ pci_measurement_update((idx), __diff); -+ -+#define PCI_WEIGHT 32 -+ -+struct pci_measurement { -+ volatile unsigned int min; -+ volatile unsigned int avg; -+ volatile unsigned int max; -+}; -+ -+enum pci_measurement_list { -+ PCI_MEASUREMENT_READ32, -+ PCI_MEASUREMENT_WRITE32, -+ PCI_MEASUREMENT_READ16, -+ PCI_MEASUREMENT_WRITE16, -+ PCI_MEASUREMENT_READ8, -+ PCI_MEASUREMENT_WRITE8, -+ PCI_MEASUREMENT_LAST, -+}; -+ -+static const char *pci_measurement_name_list[PCI_MEASUREMENT_LAST] = { -+ "READ32", -+ "WRITE32", -+ "READ16", -+ "WRITE16", -+ "READ8", -+ "WRITE8" -+}; -+static struct pci_measurement pci_measurements[PCI_MEASUREMENT_LAST]; -+ -+/* -+ * pci_measurement_update() -+ * Update an entry in the measurement array for this idx. -+ */ -+static void pci_measurement_update(int idx, int sample) -+{ -+ struct pci_measurement *pm = &pci_measurements[idx]; -+ if ((pm->min == 0) || (pm->min > sample)) { -+ pm->min = sample; -+ } -+ if (pm->max < sample) { -+ pm->max = sample; -+ } -+ pm->avg = ((pm->avg * (PCI_WEIGHT - 1)) + sample) / PCI_WEIGHT; -+} -+#endif -+ -+#if defined(PCI_USE_INTERNAL_LOCK) -+/* -+ * pci_lock_release() -+ * Release the PCI lock. -+ */ -+static void pci_lock_release(unsigned long irqflag) -+{ -+ UBICOM32_UNLOCK(PCI_LOCK_BIT); -+} -+ -+/* -+ * pci_lock_acquire() -+ * Acquire the PCI lock, spin if not available. -+ */ -+static void pci_lock_acquire(unsigned long irqflag) -+{ -+ UBICOM32_LOCK(PCI_LOCK_BIT); -+} -+#endif -+ -+/* -+ * pci_set_hrt_interrupt() -+ */ -+static inline void pci_set_hrt_interrupt(struct pci_devnode *pci_node) -+{ -+ ubicom32_set_interrupt(pci_node->dn.sendirq); -+} -+ -+/* -+ * pci_read_u32() -+ * Synchronously read 32 bits from PCI space. -+ */ -+u8 pci_read_u32(u8 pci_cmd, u32 address, u32 *data) -+{ -+ u8 status; -+ unsigned long irqflag; -+ -+ -+ /* -+ * Fill in the request. -+ */ -+ volatile struct pci_master_request lreq; -+ PCI_DECLARE_MEASUREMENT; -+ -+ lreq.pci_address = address; -+ lreq.cmd = pci_cmd; -+ lreq.byte_valid = 0xf; /* enable all bytes */ -+ -+ /* -+ * Wait for any previous request to complete and then make this request. -+ */ -+ PCI_MEASUREMENT_START(); -+ PCI_LOCK(&pci_master_lock, irqflag); -+ while (unlikely(pci_node->req == &req)) -+ ; -+ pci_node->req = &lreq; -+ pci_set_hrt_interrupt(pci_node); -+ PCI_UNLOCK(&pci_master_lock, irqflag); -+ -+ /* -+ * Wait for the result to show up. -+ */ -+ while (unlikely(pci_node->req == &lreq)) -+ ; -+ status = lreq.status; -+ if (likely(status == PCI_RESP_OK)) -+ *data = le32_to_cpu(lreq.data); -+ else -+ *data = 0; -+ PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ32); -+ return status; -+} -+ -+/* -+ * pci_write_u32() -+ * Asyncrhnously or synchronously write 32 bits to PCI master space. -+ */ -+u8 pci_write_u32(u8 pci_cmd, u32 address, u32 data) -+{ -+ unsigned long irqflag; -+ PCI_DECLARE_MEASUREMENT; -+ -+ /* -+ * Wait for any previous write or pending read to complete. -+ * -+ * We use a global data block because once we write the request -+ * we do not wait for it to complete before exiting. -+ */ -+ PCI_MEASUREMENT_START(); -+ PCI_LOCK(&pci_master_lock, irqflag); -+ while (unlikely(pci_node->req == &req)) -+ ; -+ req.pci_address = address; -+ req.data = cpu_to_le32(data); -+ req.cmd = pci_cmd; -+ req.byte_valid = 0xf; /* enable all bytes */ -+ pci_node->req = &req; -+ pci_set_hrt_interrupt(pci_node); -+ PCI_UNLOCK(&pci_master_lock, irqflag); -+ PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE32); -+ return PCI_RESP_OK; -+} -+ -+/* -+ * pci_read_u16() -+ * Synchronously read 16 bits from PCI space. -+ */ -+u8 pci_read_u16(u8 pci_cmd, u32 address, u16 *data) -+{ -+ u8 status; -+ unsigned long irqflag; -+ -+ /* -+ * Fill in the request. -+ */ -+ volatile struct pci_master_request lreq; -+ PCI_DECLARE_MEASUREMENT; -+ -+ lreq.pci_address = address & ~2; -+ lreq.cmd = pci_cmd; -+ lreq.byte_valid = (address & 2) ? 0xc : 0x3; -+ -+ /* -+ * Wait for any previous request to complete and then make this request. -+ */ -+ PCI_MEASUREMENT_START(); -+ PCI_LOCK(&pci_master_lock, irqflag); -+ while (unlikely(pci_node->req == &req)) -+ ; -+ pci_node->req = &lreq; -+ pci_set_hrt_interrupt(pci_node); -+ PCI_UNLOCK(&pci_master_lock, irqflag); -+ -+ /* -+ * Wait for the result to show up. -+ */ -+ while (unlikely(pci_node->req == &lreq)) -+ ; -+ status = lreq.status; -+ if (likely(status == PCI_RESP_OK)) { -+ lreq.data = le32_to_cpu(lreq.data); -+ *data = (u16)((address & 2) ? (lreq.data >> 16) : lreq.data); -+ } else -+ *data = 0; -+ PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ16); -+ return status; -+} -+ -+/* -+ * pci_write_u16() -+ * Asyncrhnously or synchronously write 16 bits to PCI master space. -+ */ -+u8 pci_write_u16(u8 pci_cmd, u32 address, u16 data) -+{ -+ unsigned long irqflag; -+ PCI_DECLARE_MEASUREMENT; -+ -+ /* -+ * Wait for any previous write or pending read to complete. -+ * -+ * We use a global data block because once we write the request -+ * we do not wait for it to complete before exiting. -+ */ -+ PCI_MEASUREMENT_START(); -+ PCI_LOCK(&pci_master_lock, irqflag); -+ while (unlikely(pci_node->req == &req)) -+ ; -+ req.pci_address = address & ~2; -+ req.data = (u32)data; -+ req.data = cpu_to_le32((address & 2) ? (req.data << 16) : req.data); -+ req.cmd = pci_cmd; -+ req.byte_valid = (address & 2) ? 0xc : 0x3; -+ pci_node->req = &req; -+ pci_set_hrt_interrupt(pci_node); -+ PCI_UNLOCK(&pci_master_lock, irqflag); -+ PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE16); -+ return PCI_RESP_OK; -+} -+ -+/* -+ * pci_read_u8() -+ * Synchronously read 8 bits from PCI space. -+ */ -+u8 pci_read_u8(u8 pci_cmd, u32 address, u8 *data) -+{ -+ u8 status; -+ unsigned long irqflag; -+ -+ /* -+ * Fill in the request. -+ */ -+ volatile struct pci_master_request lreq; -+ PCI_DECLARE_MEASUREMENT; -+ -+ lreq.pci_address = address & ~3; -+ lreq.cmd = pci_cmd; -+ lreq.byte_valid = 1 << (address & 0x3); -+ -+ /* -+ * Wait for any previous request to complete and then make this request. -+ */ -+ PCI_MEASUREMENT_START(); -+ PCI_LOCK(&pci_master_lock, irqflag); -+ while (unlikely(pci_node->req == &req)) -+ ; -+ pci_node->req = &lreq; -+ pci_set_hrt_interrupt(pci_node); -+ PCI_UNLOCK(&pci_master_lock, irqflag); -+ -+ /* -+ * Wait for the result to show up. -+ */ -+ while (unlikely(pci_node->req == &lreq)) -+ ; -+ status = lreq.status; -+ if (likely(status == PCI_RESP_OK)) { -+ *data = (u8)(lreq.data >> (24 - ((address & 0x3) << 3))); -+ } else -+ *data = 0; -+ PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ8); -+ return status; -+} -+ -+/* -+ * pci_write_u8() -+ * Asyncrhnously or synchronously write 8 bits to PCI master space. -+ */ -+u8 pci_write_u8(u8 pci_cmd, u32 address, u8 data) -+{ -+ unsigned long irqflag; -+ PCI_DECLARE_MEASUREMENT; -+ -+ /* -+ * Wait for any previous write or pending read to complete. -+ * -+ * We use a global data block because once we write the request -+ * we do not wait for it to complete before exiting. -+ */ -+ PCI_MEASUREMENT_START(); -+ PCI_LOCK(&pci_master_lock, irqflag); -+ while (unlikely(pci_node->req == &req)) -+ ; -+ req.pci_address = address & ~3; -+ req.data = ((u32)data << (24 - ((address & 0x3) << 3))); -+ req.cmd = pci_cmd; -+ req.byte_valid = 1 << (address & 0x3); -+ pci_node->req = &req; -+ pci_set_hrt_interrupt(pci_node); -+ PCI_UNLOCK(&pci_master_lock, irqflag); -+ PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE8); -+ return PCI_RESP_OK; -+} -+ -+unsigned int ubi32_pci_read_u32(const volatile void __iomem *addr) -+{ -+ unsigned int data; -+ pci_read_u32(PCI_CMD_MEM_READ, (u32)addr, &data); -+ return data; -+} -+EXPORT_SYMBOL(ubi32_pci_read_u32); -+ -+unsigned short ubi32_pci_read_u16(const volatile void __iomem *addr) -+{ -+ unsigned short data; -+ pci_read_u16(PCI_CMD_MEM_READ, (u32)addr, &data); -+ return data; -+} -+EXPORT_SYMBOL(ubi32_pci_read_u16); -+ -+unsigned char ubi32_pci_read_u8(const volatile void __iomem *addr) -+{ -+ unsigned char data; -+ pci_read_u8(PCI_CMD_MEM_READ, (u32)addr, &data); -+ return data; -+} -+EXPORT_SYMBOL(ubi32_pci_read_u8); -+ -+void ubi32_pci_write_u32(unsigned int val, const volatile void __iomem *addr) -+{ -+ pci_write_u32(PCI_CMD_MEM_WRITE, (u32)addr, val); -+} -+EXPORT_SYMBOL(ubi32_pci_write_u32); -+ -+void ubi32_pci_write_u16(unsigned short val, const volatile void __iomem *addr) -+{ -+ pci_write_u16(PCI_CMD_MEM_WRITE, (u32)addr, val); -+} -+EXPORT_SYMBOL(ubi32_pci_write_u16); -+ -+void ubi32_pci_write_u8(unsigned char val, const void volatile __iomem *addr) -+{ -+ pci_write_u8(PCI_CMD_MEM_WRITE, (u32)addr, val); -+} -+EXPORT_SYMBOL(ubi32_pci_write_u8); -+ -+#if defined(CONFIG_DEBUG_PCIMEASURE) -+static unsigned int pci_cycles_to_nano(unsigned int cycles, unsigned int frequency) -+{ -+ unsigned int nano = ((cycles * 1000) / (frequency / 1000000)); -+ return nano; -+} -+ -+/* -+ * pci_measurement_show() -+ * Print out the min, avg, max values for each PCI transaction type. -+ * -+ * By request, the max value is reset after each dump. -+ */ -+static int pci_measurement_show(struct seq_file *p, void *v) -+{ -+ unsigned int min, avg, max; -+ unsigned int freq = processor_frequency(); -+ int trans = *((loff_t *) v); -+ -+ if (trans == 0) { -+ seq_puts(p, "min\tavg\tmax\t(nano-seconds)\n"); -+ } -+ -+ if (trans >= PCI_MEASUREMENT_LAST) { -+ return 0; -+ } -+ -+ min = pci_cycles_to_nano(pci_measurements[trans].min, freq); -+ avg = pci_cycles_to_nano(pci_measurements[trans].avg, freq); -+ max = pci_cycles_to_nano(pci_measurements[trans].max, freq); -+ pci_measurements[trans].max = 0; -+ seq_printf(p, "%u\t%u\t%u\t%s\n", min, avg, max, pci_measurement_name_list[trans]); -+ return 0; -+} -+ -+static void *pci_measurement_start(struct seq_file *f, loff_t *pos) -+{ -+ return (*pos < PCI_MEASUREMENT_LAST) ? pos : NULL; -+} -+ -+static void *pci_measurement_next(struct seq_file *f, void *v, loff_t *pos) -+{ -+ (*pos)++; -+ if (*pos >= PCI_MEASUREMENT_LAST) -+ return NULL; -+ return pos; -+} -+ -+static void pci_measurement_stop(struct seq_file *f, void *v) -+{ -+ /* Nothing to do */ -+} -+ -+static const struct seq_operations pci_measurement_seq_ops = { -+ .start = pci_measurement_start, -+ .next = pci_measurement_next, -+ .stop = pci_measurement_stop, -+ .show = pci_measurement_show, -+}; -+ -+static int pci_measurement_open(struct inode *inode, struct file *filp) -+{ -+ return seq_open(filp, &pci_measurement_seq_ops); -+} -+ -+static const struct file_operations pci_measurement_fops = { -+ .open = pci_measurement_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+static int __init pci_measurement_init(void) -+{ -+ proc_create("pci_measurements", 0, NULL, &pci_measurement_fops); -+ return 0; -+} -+module_init(pci_measurement_init); -+#endif -+ -+static int ubi32_pci_read_config(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 *value) -+{ -+ u8 cmd; -+ u32 addr; -+ u8 data8; -+ u16 data16; -+ -+ u8 slot = PCI_SLOT(devfn); -+ u8 fn = PCI_FUNC(devfn); -+ -+ if (slot > 1) { -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ } else if (slot == 0) { -+ addr = PCI_DEV0_IDSEL + where; -+ } else { -+ addr = PCI_DEV1_IDSEL + where; -+ } -+ -+ addr += (fn << 8); -+ -+ cmd = PCI_CMD_CFG_READ; -+ if (size == 1) { -+ pci_read_u8(cmd, addr, &data8); -+ *value = (u32)data8; -+ } else if (size == 2) { -+ pci_read_u16(cmd, addr, &data16); -+ *value = (u32)data16; -+ } else { -+ pci_read_u32(cmd, addr, value); -+ } -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+static int ubi32_pci_write_config(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 value) -+{ -+ u8 cmd; -+ u32 addr; -+ u8 slot = PCI_SLOT(devfn); -+ u8 fn = PCI_FUNC(devfn); -+ -+ if (slot > 1) { -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ } else if (slot == 0) { -+ addr = PCI_DEV0_IDSEL + where; -+ } else { -+ addr = PCI_DEV1_IDSEL + where; -+ } -+ -+ addr += (fn << 8); -+ -+ cmd = PCI_CMD_CFG_WRITE; -+ if (size == 1) { -+ pci_write_u8(cmd, addr, (u8)value); -+ } else if (size == 2) { -+ pci_write_u16(cmd, addr, (u16)value); -+ } else { -+ pci_write_u32(cmd, addr, value); -+ } -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size) -+{ -+ return -EIO; -+} -+EXPORT_SYMBOL(pci_set_dma_max_seg_size); -+ -+int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask) -+{ -+ return -EIO; -+} -+EXPORT_SYMBOL(pci_set_dma_seg_boundary); -+ -+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) -+{ -+ resource_size_t start = pci_resource_start(dev, bar); -+ resource_size_t len = pci_resource_len(dev, bar); -+ unsigned long flags = pci_resource_flags(dev, bar); -+ -+ if (!len || !start) { -+ return NULL; -+ } -+ -+ if (maxlen && len > maxlen) { -+ len = maxlen; -+ } -+ -+ if (flags & IORESOURCE_IO) { -+ return ioport_map(start, len); -+ } -+ -+ if (flags & IORESOURCE_MEM) { -+ if (flags & IORESOURCE_CACHEABLE) { -+ return ioremap(start, len); -+ } -+ return ioremap_nocache(start, len); -+ } -+ return NULL; -+} -+EXPORT_SYMBOL(pci_iomap); -+ -+void pci_iounmap(struct pci_dev *dev, void __iomem *addr) -+{ -+ if ((unsigned long)addr >= VMALLOC_START && -+ (unsigned long)addr < VMALLOC_END) { -+ iounmap(addr); -+ } -+} -+EXPORT_SYMBOL(pci_iounmap); -+ -+/* -+ * From arch/arm/kernel/bios32.c -+ * -+ * PCI bios-type initialisation for PCI machines -+ * -+ * Bits taken from various places. -+ */ -+static void __init pcibios_init_hw(struct hw_pci *hw) -+{ -+ struct pci_sys_data *sys = NULL; -+ int ret; -+ int nr, busnr; -+ -+ for (nr = busnr = 0; nr < hw->nr_controllers; nr++) { -+ sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL); -+ if (!sys) -+ panic("PCI: unable to allocate sys data!"); -+ -+ sys->hw = hw; -+ sys->busnr = busnr; -+ sys->map_irq = hw->map_irq; -+ sys->resource[0] = &ioport_resource; -+ sys->resource[1] = &iomem_resource; -+ -+ ret = hw->setup(nr, sys); -+ -+ if (ret > 0) { -+ sys->bus = hw->scan(nr, sys); -+ -+ if (!sys->bus) -+ panic("PCI: unable to scan bus!"); -+ -+ busnr = sys->bus->subordinate + 1; -+ -+ list_add(&sys->node, &hw->buses); -+ } else { -+ kfree(sys); -+ if (ret < 0) -+ break; -+ } -+ } -+} -+ -+/* -+ * Swizzle the device pin each time we cross a bridge. -+ * This might update pin and returns the slot number. -+ */ -+static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 *pin) -+{ -+ struct pci_sys_data *sys = dev->sysdata; -+ int slot = 0, oldpin = *pin; -+ -+ if (sys->swizzle) -+ slot = sys->swizzle(dev, pin); -+ -+ if (debug_pci) -+ printk("PCI: %s swizzling pin %d => pin %d slot %d\n", -+ pci_name(dev), oldpin, *pin, slot); -+ return slot; -+} -+ -+/* -+ * Map a slot/pin to an IRQ. -+ */ -+static int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ struct pci_sys_data *sys = dev->sysdata; -+ int irq = -1; -+ -+ if (sys->map_irq) -+ irq = sys->map_irq(dev, slot, pin); -+ -+ if (debug_pci) -+ printk("PCI: %s mapping slot %d pin %d => irq %d\n", -+ pci_name(dev), slot, pin, irq); -+ -+ return irq; -+} -+ -+void __init pci_common_init(struct hw_pci *hw) -+{ -+ struct pci_sys_data *sys; -+ -+ INIT_LIST_HEAD(&hw->buses); -+ -+ if (hw->preinit) -+ hw->preinit(); -+ pcibios_init_hw(hw); -+ if (hw->postinit) -+ hw->postinit(); -+ -+ pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); -+ list_for_each_entry(sys, &hw->buses, node) { -+ struct pci_bus *bus = sys->bus; -+ /* -+ * Size the bridge windows. -+ */ -+ pci_bus_size_bridges(bus); -+ /* -+ * Assign resources. -+ */ -+ pci_bus_assign_resources(bus); -+ -+ /* -+ * Tell drivers about devices found. -+ */ -+ pci_bus_add_devices(bus); -+ } -+} -+ -+char * __init pcibios_setup(char *str) -+{ -+ if (!strcmp(str, "debug")) { -+ debug_pci = 1; -+ return NULL; -+ } -+ return str; -+} -+ -+/* -+ * From arch/i386/kernel/pci-i386.c: -+ * -+ * We need to avoid collisions with `mirrored' VGA ports -+ * and other strange ISA hardware, so we always want the -+ * addresses to be allocated in the 0x000-0x0ff region -+ * modulo 0x400. -+ * -+ * Why? Because some silly external IO cards only decode -+ * the low 10 bits of the IO address. The 0x00-0xff region -+ * is reserved for motherboard devices that decode all 16 -+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff, -+ * but we want to try to avoid allocating at 0x2900-0x2bff -+ * which might be mirrored at 0x0100-0x03ff.. -+ */ -+void pcibios_align_resource(void *data, struct resource *res, -+ resource_size_t size, resource_size_t align) -+{ -+ resource_size_t start = res->start; -+ -+ if (res->flags & IORESOURCE_IO && start & 0x300) -+ start = (start + 0x3ff) & ~0x3ff; -+ -+ res->start = (start + align - 1) & ~(align - 1); -+} -+ -+ -+void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) -+{ -+ if (debug_pci) -+ printk("PCI: Assigning IRQ %02d to %s\n", irq, pci_name(dev)); -+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); -+} -+ -+/* -+ * If the bus contains any of these devices, then we must not turn on -+ * parity checking of any kind. Currently this is CyberPro 20x0 only. -+ */ -+static inline int pdev_bad_for_parity(struct pci_dev *dev) -+{ -+ return (dev->vendor == PCI_VENDOR_ID_INTERG && -+ (dev->device == PCI_DEVICE_ID_INTERG_2000 || -+ dev->device == PCI_DEVICE_ID_INTERG_2010)) || -+ (dev->vendor == PCI_VENDOR_ID_ITE && -+ dev->device == PCI_DEVICE_ID_ITE_8152); -+ -+} -+ -+/* -+ * Adjust the device resources from bus-centric to Linux-centric. -+ */ -+static void __devinit -+pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev) -+{ -+ resource_size_t offset; -+ int i; -+ -+ for (i = 0; i < PCI_NUM_RESOURCES; i++) { -+ if (dev->resource[i].start == 0) -+ continue; -+ if (dev->resource[i].flags & IORESOURCE_MEM) -+ offset = root->mem_offset; -+ else -+ offset = root->io_offset; -+ -+ dev->resource[i].start += offset; -+ dev->resource[i].end += offset; -+ } -+} -+ -+static void __devinit -+pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root) -+{ -+ struct pci_dev *dev = bus->self; -+ int i; -+ -+ if (!dev) { -+ /* -+ * Assign root bus resources. -+ */ -+ for (i = 0; i < 3; i++) -+ bus->resource[i] = root->resource[i]; -+ } -+} -+ -+/* -+ * pcibios_fixup_bus - Called after each bus is probed, -+ * but before its children are examined. -+ */ -+void pcibios_fixup_bus(struct pci_bus *bus) -+{ -+ struct pci_sys_data *root = bus->sysdata; -+ struct pci_dev *dev; -+ u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | -+ PCI_COMMAND_FAST_BACK; -+ -+ pbus_assign_bus_resources(bus, root); -+ -+ /* -+ * Walk the devices on this bus, working out what we can -+ * and can't support. -+ */ -+ list_for_each_entry(dev, &bus->devices, bus_list) { -+ u16 status; -+ -+ pdev_fixup_device_resources(root, dev); -+ -+ pci_read_config_word(dev, PCI_STATUS, &status); -+ -+ /* -+ * If any device on this bus does not support fast back -+ * to back transfers, then the bus as a whole is not able -+ * to support them. Having fast back to back transfers -+ * on saves us one PCI cycle per transaction. -+ */ -+ if (!(status & PCI_STATUS_FAST_BACK)) -+ features &= ~PCI_COMMAND_FAST_BACK; -+ -+ if (pdev_bad_for_parity(dev)) -+ features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); -+ -+ switch (dev->class >> 8) { -+ case PCI_CLASS_BRIDGE_PCI: -+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status); -+ status |= PCI_BRIDGE_CTL_PARITY | -+ PCI_BRIDGE_CTL_MASTER_ABORT; -+ status &= ~(PCI_BRIDGE_CTL_BUS_RESET | -+ PCI_BRIDGE_CTL_FAST_BACK); -+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status); -+ break; -+ -+ case PCI_CLASS_BRIDGE_CARDBUS: -+ pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL, -+ &status); -+ status |= PCI_CB_BRIDGE_CTL_PARITY | -+ PCI_CB_BRIDGE_CTL_MASTER_ABORT; -+ pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL, -+ status); -+ break; -+ } -+ } -+ -+ /* -+ * Now walk the devices again, this time setting them up. -+ */ -+ list_for_each_entry(dev, &bus->devices, bus_list) { -+ u16 cmd; -+ -+ pci_read_config_word(dev, PCI_COMMAND, &cmd); -+ cmd |= features; -+ pci_write_config_word(dev, PCI_COMMAND, cmd); -+ -+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, -+ L1_CACHE_BYTES >> 2); -+ } -+ -+ /* -+ * Propagate the flags to the PCI bridge. -+ */ -+ if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) { -+ if (features & PCI_COMMAND_FAST_BACK) -+ bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK; -+ if (features & PCI_COMMAND_PARITY) -+ bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY; -+ } -+ -+ /* -+ * Report what we did for this bus -+ */ -+ printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n", -+ bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); -+} -+/* -+ * Convert from Linux-centric to bus-centric addresses for bridge devices. -+ */ -+void -+pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, -+ struct resource *res) -+{ -+ struct pci_sys_data *root = dev->sysdata; -+ unsigned long offset = 0; -+ -+ if (res->flags & IORESOURCE_IO) -+ offset = root->io_offset; -+ if (res->flags & IORESOURCE_MEM) -+ offset = root->mem_offset; -+ -+ region->start = res->start - offset; -+ region->end = res->end - offset; -+} -+ -+void __devinit -+pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, -+ struct pci_bus_region *region) -+{ -+ struct pci_sys_data *root = dev->sysdata; -+ unsigned long offset = 0; -+ -+ if (res->flags & IORESOURCE_IO) -+ offset = root->io_offset; -+ if (res->flags & IORESOURCE_MEM) -+ offset = root->mem_offset; -+ -+ res->start = region->start + offset; -+ res->end = region->end + offset; -+} -+ -+#ifdef CONFIG_HOTPLUG -+EXPORT_SYMBOL(pcibios_fixup_bus); -+EXPORT_SYMBOL(pcibios_resource_to_bus); -+EXPORT_SYMBOL(pcibios_bus_to_resource); -+#endif -+ -+/** -+ * pcibios_enable_device - Enable I/O and memory. -+ * @dev: PCI device to be enabled -+ */ -+int pcibios_enable_device(struct pci_dev *dev, int mask) -+{ -+ u16 cmd, old_cmd; -+ int idx; -+ struct resource *r; -+ -+ pci_read_config_word(dev, PCI_COMMAND, &cmd); -+ old_cmd = cmd; -+ for (idx = 0; idx < 6; idx++) { -+ /* Only set up the requested stuff */ -+ if (!(mask & (1 << idx))) -+ continue; -+ -+ r = dev->resource + idx; -+ if (!r->start && r->end) { -+ printk(KERN_ERR "PCI: Device %s not available because" -+ " of resource collisions\n", pci_name(dev)); -+ return -EINVAL; -+ } -+ if (r->flags & IORESOURCE_IO) -+ cmd |= PCI_COMMAND_IO; -+ if (r->flags & IORESOURCE_MEM) -+ cmd |= PCI_COMMAND_MEMORY; -+ } -+ -+ /* -+ * Bridges (eg, cardbus bridges) need to be fully enabled -+ */ -+ if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) -+ cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; -+ -+ if (cmd != old_cmd) { -+ printk("PCI: enabling device %s (%04x -> %04x)\n", -+ pci_name(dev), old_cmd, cmd); -+ pci_write_config_word(dev, PCI_COMMAND, cmd); -+ } -+ return 0; -+} -+ -+ -+struct pci_ops ubi32_pci_ops = { -+ .read = ubi32_pci_read_config, -+ .write = ubi32_pci_write_config, -+}; -+ -+static struct pci_bus *ubi32_pci_scan_bus(int nr, struct pci_sys_data *sys) -+{ -+ return pci_scan_bus(sys->busnr, &ubi32_pci_ops, sys); -+} -+ -+#define UBI32_PCI_MEM_BASE PCI_DEV_REG_BASE -+#define UBI32_PCI_MEM_LEN 0x80000000 -+ -+#define UBI32_PCI_IO_BASE 0x0 -+#define UBI32_PCI_IO_END 0x0 -+ -+static struct resource ubi32_pci_mem = { -+ .name = "PCI memory space", -+ .start = UBI32_PCI_MEM_BASE, -+ .end = UBI32_PCI_MEM_BASE + UBI32_PCI_MEM_LEN - 1, -+ .flags = IORESOURCE_MEM, -+}; -+ -+static struct resource ubi32_pci_io = { -+ .name = "PCI IO space", -+ .start = UBI32_PCI_IO_BASE, -+ .end = UBI32_PCI_IO_END, -+ .flags = IORESOURCE_IO, -+}; -+ -+static int __init ubi32_pci_setup(int nr, struct pci_sys_data *sys) -+{ -+ if (nr > 0) -+ return 0; -+ -+ request_resource(&iomem_resource, &ubi32_pci_mem); -+ request_resource(&ioport_resource, &ubi32_pci_io); -+ -+ sys->resource[0] = &ubi32_pci_io; -+ sys->resource[1] = &ubi32_pci_mem; -+ sys->resource[2] = NULL; -+ -+ return 1; -+} -+ -+static void __init ubi32_pci_preinit(void) -+{ -+} -+ -+static int __init ubi32_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ return pci_node->dn.recvirq; -+} -+ -+struct hw_pci ubi32_pci __initdata = { -+ .nr_controllers = 1, -+ .preinit = ubi32_pci_preinit, -+ .setup = ubi32_pci_setup, -+ .scan = ubi32_pci_scan_bus, -+ .map_irq = ubi32_pci_map_irq, -+}; -+ -+static int __init ubi32_pci_init(void) -+{ -+ pci_node = (struct pci_devnode *)devtree_find_node("pci"); -+ if (pci_node == NULL) { -+ printk(KERN_WARNING "PCI init failed\n"); -+ return -ENOSYS; -+ } -+ pci_common_init(&ubi32_pci); -+ return 0; -+} -+ -+subsys_initcall(ubi32_pci_init); -+ -+/* -+ * workaround for dual PCI card interrupt -+ */ -+#define PCI_COMMON_INT_BIT (1 << 19) -+void ubi32_pci_int_wr(void) -+{ -+ volatile unsigned int pci_int_line; -+ pci_int_line = UBICOM32_IO_PORT(RB)->gpio_in; -+ if (!(pci_int_line & PCI_COMMON_INT_BIT)) -+ { -+ ubicom32_set_interrupt(pci_node->dn.recvirq); -+ } -+} -+EXPORT_SYMBOL(ubi32_pci_int_wr); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/plio.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/plio.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/plio.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/plio.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,92 @@ -+/* -+ * plio.c -+ * PLIO state machine support functions -+ * -+ * Copyright © 2009 Ubicom Inc. . All rights reserved. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can -+ * redistribute it and/or modify it under the terms of the GNU General -+ * Public License as published by the Free Software Foundation, either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ * See the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * plio_reset -+ * Select and reset PLIO function -+ */ -+static void plio_reset(const plio_fctl_t *plio_fctl) { -+ plio_io_function_t plio_function = { -+ .fn_sel = PLIO_FN, -+ .fn_reset = 1, -+ }; -+ -+ /* -+ * enable extension port -+ */ -+ PEXT_NBR->function = plio_function; -+ -+ /* -+ * program clock dividers -+ */ -+ PLIO_NBR->fctl2 = plio_fctl->fctl2; -+ -+ /* -+ * select plio function and assert function reset -+ */ -+ plio_function.br_thread = thread_get_self(); -+ plio_function.fn_reset = 1; -+ PLIO_NBR->function = plio_function; -+ -+ /* -+ * program plio controls -+ */ -+ PLIO_NBR->fctl0 = plio_fctl->fctl0; -+ PLIO_NBR->fctl1 = plio_fctl->fctl1; -+ -+ /* -+ * deassert function reset -+ */ -+ plio_function.fn_reset = 0; -+ PLIO_NBR->function = plio_function; -+} -+ -+/* -+ * plio_init -+ * configure and initialize PLIO. -+ */ -+void plio_init(const plio_fctl_t *plio_fctl, const plio_config_t *plio_config, const plio_sram_t plio_sram_cfg[], int sram_cfg_size){ -+ /* -+ * first reset to start plio clock -+ */ -+ plio_reset(plio_fctl); -+ -+ udelay(1); -+ -+ /* -+ * configure pfsm -+ */ -+ PLIO_NBR->fctl0.pfsm_prog = 1; -+ memcpy(PLIO_BR->pfsm_sram, plio_sram_cfg, sram_cfg_size); -+ PLIO_NBR->fctl0.pfsm_prog = 0; -+ -+ /* -+ * program rest of plio -+ */ -+ memcpy(&PLIO_BR->config, plio_config, sizeof(plio_config_t)); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/profile.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/profile.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/profile.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/profile.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,549 @@ -+/* -+ * arch/ubicom32/mach-common/profile.c -+ * Implementation for Ubicom32 Profiler -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include "profile.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * spacs for all memory blocks so we can hold locks for short time when walking tables -+ */ -+#define PROFILE_NUM_MAPS 5000 -+static struct profile_map profile_pm[PROFILE_NUM_MAPS]; -+ -+static struct profilenode *node = NULL; -+static int profile_first_packet = 1; -+ -+static int profile_open(struct inode *inode, struct file *filp) -+{ -+ if (!node) { -+ return -ENOENT; -+ } -+ node->busy = 1; -+ if (!node->enabled) { -+ node->enabled = 1; -+ node->busy = 0; -+ profile_first_packet = 1; -+ return 0; -+ } -+ node->busy = 0; -+ return -EBUSY; -+} -+ -+static int profile_sequence_num; -+ -+/* -+ * make a packet full of sample data -+ */ -+static int profile_make_data_packet(char *buf, int count) -+{ -+ int samples; /* number of samples requested */ -+ int i; -+ struct profile_header ph; -+ char *ptr; -+ -+ if (count < sizeof(struct profile_header) + sizeof(struct profile_sample)) { -+ return -EINVAL; -+ } -+ -+ /* -+ * fill in the packet header -+ */ -+ memset(&ph, 0, sizeof(struct profile_header)); -+ ph.magic = PROF_MAGIC + PROFILE_VERSION; -+ ph.header_size = sizeof(struct profile_header); -+ ph.clocks = node->clocks; -+ for (i = 0; i < PROFILE_MAX_THREADS; ++i) { -+ ph.instruction_count[i] = node->inst_count[i]; -+ } -+ ph.profile_instructions = 0; -+ ph.enabled = node->enabled_threads; -+ ph.hrt = node->hrt; -+ ph.high = 0; -+ ph.profiler_thread = node->profiler_thread; -+ ph.clock_freq = node->clock_freq; -+ ph.seq_num = profile_sequence_num++; -+ ph.cpu_id = node->cpu_id; -+ ph.perf_counters[0] = node->stats[0]; -+ ph.perf_counters[1] = node->stats[1]; -+ ph.perf_counters[2] = node->stats[2]; -+ ph.perf_counters[3] = node->stats[3]; -+ ph.ddr_freq = node->ddr_freq; -+ -+ ptr = buf + sizeof(struct profile_header); -+ -+ samples = (count - sizeof(struct profile_header)) / sizeof(struct profile_sample); -+ for (i = 0; i < samples && node->count; ++i) { -+ if (copy_to_user(ptr, &node->samples[node->tail], sizeof(struct profile_sample)) != 0) { -+ return -EFAULT; -+ } -+ node->count--; -+ node->tail++; -+ if (node->tail >= node->max_samples) { -+ node->tail = 0; -+ } -+ ptr += sizeof(struct profile_sample); -+ } -+ ph.sample_count = i; -+ if (copy_to_user(buf, &ph, sizeof(struct profile_header)) != 0) { -+ return -EFAULT; -+ } -+ if (ph.sample_count == 0) -+ return 0; -+ else -+ return sizeof(struct profile_header) + ph.sample_count * sizeof(struct profile_sample); -+} -+ -+static void profile_get_memory_stats(unsigned int *total_free, unsigned int *max_free) -+{ -+ struct list_head *p; -+ struct zone *zone; -+ unsigned int size; -+ -+ *total_free = 0; -+ *max_free = 0; -+ -+ /* -+ * get all the free regions. In each zone, the array of free_area lists contains the first page of each frame of size 1 << order -+ */ -+ for_each_zone(zone) { -+ unsigned long order, flags, i; -+ -+ if (!populated_zone(zone)) -+ continue; -+ -+ if (!is_normal(zone)) -+ continue; -+ -+ spin_lock_irqsave(&zone->lock, flags); -+ for_each_migratetype_order(order, i) { -+ size = ((1 << order) << PAGE_SHIFT) >> 10; -+ list_for_each(p, &(zone->free_area[order].free_list[i])) { -+ if (size > *max_free) { -+ *max_free = size; -+ } -+ *total_free += size; -+ } -+ } -+ spin_unlock_irqrestore(&zone->lock, flags); -+ } -+} -+ -+struct profile_counter_pkt profile_builtin_stats[] = -+{ -+ { -+ "Free memory(KB)", 0 -+ }, -+ { -+ "Max free Block(KB)", 0 -+ } -+}; -+ -+/* -+ * make a packet full of performance counters -+ */ -+static char prof_pkt[PROFILE_MAX_PACKET_SIZE]; -+static int profile_make_stats_packet(char *buf, int count) -+{ -+ char *ptr = prof_pkt; -+ struct profile_header_counters hdr; -+ int stat_count = 0; -+ int i; -+ unsigned int total_free, max_free; -+ int builtin_count = sizeof(profile_builtin_stats) / sizeof(struct profile_counter_pkt); -+ -+ if (count > PROFILE_MAX_PACKET_SIZE) { -+ count = PROFILE_MAX_PACKET_SIZE; -+ } -+ stat_count = (count - sizeof(struct profile_header_counters)) / sizeof (struct profile_counter_pkt); -+ stat_count -= builtin_count; -+ -+ if (stat_count <= 0) { -+ return 0; -+ } -+ -+ if (stat_count > node->num_counters) { -+ stat_count = node->num_counters; -+ } -+ -+ hdr.magic = PROF_MAGIC_COUNTERS; -+ hdr.ultra_sample_time = node->clocks; -+ hdr.ultra_count = stat_count; -+ hdr.linux_sample_time = UBICOM32_IO_TIMER->sysval; -+ hdr.linux_count = builtin_count; -+ memcpy(ptr, (void *)&hdr, sizeof(struct profile_header_counters)); -+ ptr += sizeof(struct profile_header_counters); -+ -+ -+ for (i = 0; i < stat_count; ++i) { -+ memcpy(ptr, (void *)(&(node->counters[i])), sizeof(struct profile_counter)); -+ ptr += sizeof(struct profile_counter); -+ } -+ -+ /* -+ * built in statistics -+ */ -+ profile_get_memory_stats(&total_free, &max_free); -+ profile_builtin_stats[0].value = total_free; -+ profile_builtin_stats[1].value = max_free; -+ memcpy(ptr, (void *)profile_builtin_stats, sizeof(profile_builtin_stats)); -+ ptr += sizeof(profile_builtin_stats); -+ -+ if (copy_to_user(buf, prof_pkt, ptr - prof_pkt) != 0) { -+ return -EFAULT; -+ } -+ return ptr - prof_pkt; -+} -+ -+/* -+ * return a udp packet ready to send to the profiler tool -+ * when there are no packets left to make, return 0 -+ */ -+static int profile_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) -+{ -+ int result = 0; -+ if (!node) { -+ return -ENOENT; -+ } -+ node->busy = 1; -+ if (!node->enabled) { -+ node->busy = 0; -+ return -EPERM; -+ } -+ if (!node->samples) { -+ node->busy = 0; -+ return -ENOMEM; -+ } -+ -+ if (profile_first_packet) { -+ result = profile_make_stats_packet(buf, count); -+ profile_first_packet = 0; -+ } -+ if (result == 0) { -+ result = profile_make_data_packet(buf, count); -+ if (result == 0) { -+ profile_first_packet = 1; -+ } -+ } -+ node->busy = 0; -+ return result; -+ -+} -+ -+static int profile_release(struct inode *inode, struct file *filp) -+{ -+ if (!node) { -+ return -ENOENT; -+ } -+ node->busy = 1; -+ if (node->enabled) { -+ node->enabled = 0; -+ node->count = 0; -+ node->tail = node->head; -+ node->busy = 0; -+ return 0; -+ } -+ node->busy = 0; -+ profile_first_packet = 1; -+ return -EBADF; -+} -+ -+static const struct file_operations profile_fops = { -+ .open = profile_open, -+ .read = profile_read, -+ .release = profile_release, -+}; -+ -+static int page_aligned(void *x) -+{ -+ return !((unsigned int)x & ((1 << PAGE_SHIFT) - 1)); -+} -+ -+static int profile_maps_open(struct inode *inode, struct file *filp) -+{ -+ struct rb_node *rb; -+ int num = 0; -+ int slab_start; -+ struct vm_area_struct *vma; -+ int type = PROFILE_MAP_TYPE_UNKNOWN; -+ int flags, i; -+ struct list_head *p; -+ struct zone *zone; -+ -+ /* -+ * get the slab data (first so dups will show up as vmas) -+ */ -+ slab_start = num; -+ num += kmem_cache_block_info("size-512", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); -+ num += kmem_cache_block_info("size-1024", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); -+ num += kmem_cache_block_info("size-2048", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); -+ num += kmem_cache_block_info("size-4096", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); -+ num += kmem_cache_block_info("size-8192", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); -+ -+ for (i = slab_start; i < num; ++i) { -+ profile_pm[i].type_size |= PROFILE_MAP_TYPE_SMALL << PROFILE_MAP_TYPE_SHIFT; -+ } -+ -+ slab_start = num; -+ num += kmem_cache_block_info("dentry", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); -+ num += kmem_cache_block_info("inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); -+ num += kmem_cache_block_info("sysfs_dir_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); -+ num += kmem_cache_block_info("proc_inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num); -+ -+ for (i = slab_start; i < num; ++i) { -+ profile_pm[i].type_size |= PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT; -+ } -+ -+ /* -+ * get all the vma regions (allocated by mmap, most likely -+ */ -+#if 0 -+ down_read(&nommu_vma_sem); -+ for (rb = rb_first(&nommu_vma_tree); rb && num < PROFILE_NUM_MAPS; rb = rb_next(rb)) { -+ vma = rb_entry(rb, struct vm_area_struct, vm_rb); -+ profile_pm[num].start = (vma->vm_start - SDRAMSTART) >> PAGE_SHIFT; -+ profile_pm[num].type_size = (vma->vm_end - vma->vm_start + (1 << PAGE_SHIFT) - 1) >> PAGE_SHIFT; -+ flags = vma->vm_flags & 0xf; -+ if (flags == (VM_READ | VM_EXEC)) { -+ type = PROFILE_MAP_TYPE_TEXT; -+ } else if (flags == (VM_READ | VM_WRITE | VM_EXEC)) { -+ type = PROFILE_MAP_TYPE_STACK; -+ } else if (flags == (VM_READ | VM_WRITE)) { -+ type = PROFILE_MAP_TYPE_APP_DATA; -+ } -+ profile_pm[num].type_size |= type << PROFILE_MAP_TYPE_SHIFT; -+ num++; -+ } -+ up_read(&nommu_vma_sem); -+ if (rb) { -+ return -ENOMEM; -+ } -+#endif -+ -+ /* -+ * get all the free regions. In each zone, the array of free_area lists contains the first page of each frame of size 1 << order -+ */ -+ for_each_zone(zone) { -+ unsigned long order, flags, i; -+ struct page *page; -+ -+ if (!populated_zone(zone)) -+ continue; -+ -+ if (!is_normal(zone)) -+ continue; -+ -+ spin_lock_irqsave(&zone->lock, flags); -+ for_each_migratetype_order(order, i) { -+ list_for_each(p, &(zone->free_area[order].free_list[i])) { -+ page = list_entry(p, struct page, lru); -+ profile_pm[num].start = ((page_to_phys(page) - SDRAMSTART) >> PAGE_SHIFT) - 0x40; -+ profile_pm[num].type_size = (PROFILE_MAP_TYPE_FREE << PROFILE_MAP_TYPE_SHIFT) | order; -+ num++; -+ if (num >= PROFILE_NUM_MAPS) { -+ spin_unlock_irqrestore(&zone->lock, flags); -+ return -ENOMEM; -+ } -+ } -+ } -+ spin_unlock_irqrestore(&zone->lock, flags); -+ } -+ -+ /* -+ * get the filesystem inodes -+ */ -+ list_for_each(p, &(super_blocks)) { -+ struct super_block *sb; -+ struct list_head *q; -+ if (num >= PROFILE_NUM_MAPS) -+ break; -+ sb = list_entry(p, struct super_block, s_list); -+ if (page_aligned(sb)) { -+ profile_pm[num].start = ((unsigned int)sb - SDRAMSTART) >> PAGE_SHIFT; -+ profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT); -+ num++; -+ } -+ list_for_each(q, &(sb->s_inodes)) { -+ struct inode *in; -+ if (num >= PROFILE_NUM_MAPS) -+ break; -+ in = list_entry(q, struct inode, i_sb_list); -+ if (page_aligned(in)) { -+ profile_pm[num].start = ((unsigned int)in - SDRAMSTART) >> PAGE_SHIFT; -+ profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT); -+ num++; -+ } -+ } -+ } -+ -+ /* -+ * get the buffer cache pages -+ */ -+ for (i = 0; i < num_physpages && num < PROFILE_NUM_MAPS; ++i) { -+ if ((mem_map + i)->flags & (1 << PG_lru)) { -+ int start = i; -+ while ((mem_map + i)->flags & (1 << PG_lru) && i < num_physpages) -+ i++; -+ profile_pm[num].start = start; -+ profile_pm[num].type_size = (i - start) | (PROFILE_MAP_TYPE_CACHE << PROFILE_MAP_TYPE_SHIFT); -+ num++; -+ } -+ } -+ -+ filp->private_data = (void *)num; -+ return 0; -+} -+ -+/* -+ * return one packet of map data, or 0 if all maps have been returned already -+ */ -+static int profile_maps_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) -+{ -+ struct profile_header_maps header; -+ char *p = buf + sizeof(header); -+ int total = (int)filp->private_data; -+ -+ header.count = (count - sizeof(header)) / sizeof(struct profile_map); -+ if (header.count > PROFILE_MAX_MAPS) { -+ header.count = PROFILE_MAX_MAPS;; -+ } -+ if (header.count > total - *f_pos) { -+ header.count = total - *f_pos; -+ } -+ -+ if (header.count == 0) { -+ return 0; -+ } -+ -+ header.magic = PROF_MAGIC_MAPS; -+ header.page_shift = PAGE_SHIFT; -+ -+ if (copy_to_user(buf, &header, sizeof(header)) != 0) { -+ return -EFAULT; -+ } -+ if (copy_to_user(p, (void *)&profile_pm[*f_pos], sizeof(struct profile_map) * header.count) != 0) { -+ return -EFAULT; -+ } -+ *f_pos += header.count; -+ -+ return sizeof(header) + sizeof(struct profile_map) * header.count; -+} -+ -+static int profile_maps_release(struct inode *inode, struct file *filp) -+{ -+ return 0; -+} -+ -+static const struct file_operations profile_maps_fops = { -+ .open = profile_maps_open, -+ .read = profile_maps_read, -+ .release = profile_maps_release, -+}; -+ -+static int profile_rate_show(struct seq_file *m, void *v) -+{ -+ if (node) { -+ seq_printf(m, "%d samples per second. %d virtual counters.\n", node->rate, node->num_counters); -+ } else { -+ seq_printf(m, "Profiler is not initialized.\n"); -+ } -+ return 0; -+} -+ -+static int profile_rate_open(struct inode *inode, struct file *filp) -+{ -+ return single_open(filp, profile_rate_show, NULL); -+} -+ -+static int profile_rate_write(struct file *filp, const char *buf, size_t len, loff_t *off) -+{ -+ *off = 0; -+ return 0; -+} -+ -+static const struct file_operations profile_rate_fops = { -+ .open = profile_rate_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .write = profile_rate_write, -+}; -+ -+int ubi32_profile_init_module(void) -+{ -+ struct proc_dir_entry *pdir; -+ -+ /* -+ * find the device -+ */ -+ node = (struct profilenode *)devtree_find_node("profiler"); -+ if (!node) { -+ printk(KERN_INFO "Profiler does not exist.\n"); -+ return -ENODEV; -+ } -+ -+ /* -+ * allocate the sample buffer -+ */ -+ node->max_samples = PROFILE_MAX_SAMPLES; -+ node->samples = kmalloc(node->max_samples * sizeof(struct profile_sample), GFP_KERNEL); -+ if (!node->samples) { -+ printk(KERN_INFO "Profiler sample buffer kmalloc failed.\n"); -+ return -ENOMEM; -+ } -+ -+ /* -+ * connect to the file system -+ */ -+ pdir = proc_mkdir("profile", NULL); -+ if (!pdir) { -+ return -ENOMEM; -+ } -+ if (!proc_create("data", 0, pdir, &profile_fops)) { -+ return -ENOMEM; -+ } -+ if (!proc_create("rate", 0, pdir, &profile_rate_fops)) { -+ return -ENOMEM; -+ } -+ if (!proc_create("maps", 0, pdir, &profile_maps_fops)) { -+ return -ENOMEM; -+ } -+ return 0; -+} -+ -+ -+module_init(ubi32_profile_init_module); -+ -+MODULE_AUTHOR("David Fotland"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/profile.h linux-2.6.30.10-ubi/arch/ubicom32/mach-common/profile.h ---- linux-2.6.30.10/arch/ubicom32/mach-common/profile.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/profile.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,82 @@ -+/* -+ * arch/ubicom32/mach-common/profile.h -+ * Private data for the profile module -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include "profpkt.h" -+ -+#ifndef _PROFILE_H_ -+#define _PROFILE_H_ -+ -+#define PROFILE_MAX_THREADS 16 -+#define PROFILE_MAX_SAMPLES 1024 -+ -+struct profile_sample; -+struct oprofile_sample; -+ -+/* -+ * values chosen so all counter values fit in a single UDP packet -+ */ -+#define PROFILE_NODE_MAX_COUNTERS 32 -+ -+struct profile_counter { -+ char name[PROFILE_COUNTER_NAME_LENGTH]; -+ unsigned int value; -+}; -+ -+struct profilenode { -+ struct devtree_node dn; -+ volatile u32_t enabled; /* Is the profiler enabled to take samples? */ -+ volatile u32_t busy; /* set when the samples are being read by the driver */ -+ volatile u32_t rate; /* What is the sampling rate? */ -+ volatile u32_t enabled_threads; /* which threads were enabled at the last sample time */ -+ volatile u32_t hrt; /* HRT threads */ -+ volatile u32_t profiler_thread; /* thread running the profile sampler */ -+ volatile u32_t clocks; /* system clock timer at last sample */ -+ volatile u32_t clock_freq; /* clock frequency in Hz */ -+ volatile u32_t ddr_freq; /* memory frequency */ -+ volatile u32_t cpu_id; /* chip_id register */ -+ volatile u32_t inst_count[PROFILE_MAX_THREADS]; /* sampled instruction counts at most recent sample */ -+ volatile u32_t stats[4]; /* contents of the cache statistics counters */ -+ volatile u16_t head; /* sample taker puts samples here */ -+ volatile u16_t tail; /* packet filler takes samples here */ -+ volatile u16_t count; /* number of valid samples */ -+ volatile u16_t max_samples; /* how many samples can be in the samples array */ -+ struct profile_sample *samples; /* samples array allocated by the linux driver */ -+ volatile u32_t num_counters; /* how many registered performance counters */ -+ volatile struct profile_counter counters[PROFILE_NODE_MAX_COUNTERS]; -+ -+ /* unimplemented interface for future oprofile work */ -+ volatile u16_t oprofile_head; /* sample taker puts samples here */ -+ volatile u16_t oprofile_tail; /* packet filler takes samples here */ -+ volatile u16_t oprofile_count; /* how many oprofile sampels are are in use */ -+ volatile u16_t oprofile_max_samples; /* samples array size for oprofile samples */ -+ struct oprofile_sample *oprofile_samples; /* oprofile sample buffer */ -+}; -+ -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/profpkt.h linux-2.6.30.10-ubi/arch/ubicom32/mach-common/profpkt.h ---- linux-2.6.30.10/arch/ubicom32/mach-common/profpkt.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/profpkt.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,158 @@ -+ -+/* -+ * arch/ubicom32/mach-common/profpkt.c -+ * Ubicom32 Profiler packet formats for communication between the linux proc driver and the profiler display tool -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#define PROFILE_PORT 51080 -+#define PROFILE_POSIX_NAME_LENGTH 32 -+ -+/* -+ * profile UDP packet format for communicating between ip3k and host -+ * -+ * every packet starts with a header, followed by samples. -+ * samples are only taken for non-hrt threads that are -+ * active -+ */ -+#define PROF_MAGIC 0x3ea0 -+#define PROF_MAGIC_COUNTERS 0x9ea0 -+#define PROF_MAGIC_MAPS 0xaea0 -+ -+/* -+ * Versions (31 max): -+ * 1 to 4 were before 6.0 release, development versions -+ * 5 was forward compatible version, shipped with 6.0 and 6.1 -+ * 6 adds heap packets, and clock_freq to header, shipped with 6.2 -+ * 7 adds a sequence numbers to check for dropped packets, shipped with 6.3.5 -+ * 8 adds mqueue timing information, shipped with 6.3.5 -+ * 9 adds sdram heap size information, shipped with 6.4 -+ * 10 adds heapmem heap callers and long latency stack traces. shipped with 6.4 -+ * 11 adds support for Mars (IP5K). shipped with 6.10 -+ * 12 adds more support for Mars. Shipped with 7.0 -+ * 13 adds per sample latency measurement. Shipped with 7.2 -+ * 14 changes the heap format and adds a string packet. Shipped with 7.4 -+ * 15 adds dsr stats and posix. shipped with 7.6 -+ * 16 corrects maximum packet count for Ares. ships with 7.9 -+ * 17 adds a5 register value to sample -+ */ -+ -+#define PROFILE_VERSION 17 -+#define PROFILE_MAX_PACKET_SIZE 1440 -+ -+#define PROFILE_MAX_THREADS 16 -+ -+/* -+ * each packet starts with a profile_header, then sample_count samples -+ * samples are gprof samples of pc, the return address, condition codes, and -+ * active threads -+ */ -+struct profile_header { -+ u16_t magic; /* magic number and version */ -+ u8_t header_size; /* number of bytes in profile header */ -+ u8_t sample_count; /* number of samples in the packet */ -+ u32_t clocks; /* clock counter value */ -+ u32_t instruction_count[PROFILE_MAX_THREADS]; -+ /* instructions executed per thread */ -+ u32_t profile_instructions; /* instructions executed by profiler mainline */ -+ u16_t enabled; /* which threads are enabled */ -+ u16_t hrt; /* which threads are hrt */ -+ u16_t high; /* which threads are high priority */ -+ u16_t profiler_thread; /* which thread runs the profiler */ -+ u32_t heap_free; /* current free on-cihp heap space in bytes */ -+ u32_t heap_low_water; /* on-chip heap low water mark */ -+ u32_t netpage_free; /* number of free on-chip net pages */ -+ u32_t netpage_low_water; /* low water mark on free on-chip netpages */ -+ u32_t min_sp[PROFILE_MAX_THREADS]; -+ /* stack pointer values per thread */ -+ u32_t clock_freq; /* clock frequency (Hz) of system being analyzed */ -+ u32_t seq_num; /* to detect dropped profiler packets */ -+ u32_t timing_sequence; /* sample number since boot */ -+ u32_t timing_interval; /* second per sample timing interval */ -+ u32_t timing_worst_time; /* duration of longest finction called, in core clocks */ -+ u32_t timing_function; /* address of longest function */ -+ u32_t timing_average; /* average time of all functions in last interval */ -+ u32_t timing_count; /* number of functions called in last interval */ -+ u32_t extheap_free; /* current free extmem heap space in bytes */ -+ u32_t extheap_low_water; /* extmem heap low water mark */ -+ u32_t cpu_id; /* CHIP_ID register contents */ -+ u32_t perf_counters[4]; /* contents of the CPU performance counters */ -+ u8_t perf_config[4]; /* what is being counted */ -+ u32_t ddr_freq; /* DDR clock frequency */ -+ u32_t extnetpage_free; /* number of free off chip net pages */ -+ u32_t extnetpage_low_water; /* low water mark on off-chip free netpages */ -+ u32_t dsr_max_latency; /* max time to process a dsr interrupt, in clocks, since last packet */ -+ u32_t dsr_ave_latency; /* average dsr latency over last DSR_STATS_RECENT_COUNT interrupts */ -+ u32_t dsr_count; /* number of dsr interrupts since last packet */ -+}; -+ -+struct profile_header_counters { -+ u16_t magic; -+ u16_t ultra_count; /* how many ultra counters follow this */ -+ u32_t ultra_sample_time; /* in chip clocks */ -+ u32_t linux_count; /* how many linux counters follow this */ -+ u32_t linux_sample_time; -+}; -+ -+/* -+ * values chosen so all counter values fit in a single 1400 byte UDP packet -+ */ -+#define PROFILE_COUNTER_NAME_LENGTH 20 -+#define PROFILE_MAX_COUNTERS ((PROFILE_MAX_PACKET_SIZE - sizeof(struct profile_header_counters)) / (PROFILE_COUNTER_NAME_LENGTH + 4)) -+ -+struct profile_counter_pkt { -+ char name[PROFILE_COUNTER_NAME_LENGTH]; -+ unsigned int value; -+}; -+ -+/* -+ * send memory maps from linux to profiler tool -+ */ -+ -+struct profile_header_maps { -+ u16_t magic; -+ u16_t count; -+ u32_t page_shift; -+}; -+ -+#define PROFILE_MAP_NUM_TYPES 32 -+ -+/* types 0-15: size field is order. True size is 2^order */ -+#define PROFILE_MAP_TYPE_UNKNOWN 0 -+#define PROFILE_MAP_TYPE_FREE 1 -+#define PROFILE_MAP_TYPE_SMALL 2 -+#define PROFILE_MAP_TYPE_FS 3 -+/* types 16-31: size field is pages. True size is (1 << PAGE_SHIFT) * size */ -+#define PROFILE_MAP_SIZE_TYPE 16 -+#define PROFILE_MAP_TYPE_TEXT 16 -+#define PROFILE_MAP_TYPE_STACK 17 -+#define PROFILE_MAP_TYPE_APP_DATA 18 -+#define PROFILE_MAP_TYPE_CACHE 19 -+#define PROFILE_MAP_RESERVED 24 -+ -+#define PROFILE_MAP_TYPE_SHIFT 11 -+#define PROFILE_MAP_SIZE_MASK 0x7ff -+ -+struct profile_map { -+ u16_t start; /* start page number of segment, relative to start of DRAM */ -+ u16_t type_size; /* type (4 bits) of the segment and size in pages (12 bits) */ -+}; -+ -+#define PROFILE_MAX_MAPS (PROFILE_MAX_PACKET_SIZE - sizeof(struct profile_header_maps)) / sizeof(struct profile_map) -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/ring_tio.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ring_tio.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/ring_tio.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ring_tio.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,123 @@ -+/* -+ * arch/ubicom32/mach-common/ring_tio.c -+ * Generic initialization for UIO Ubicom32 Ring -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include -+ -+#include -+#include -+ -+static const char *ring_tio_driver_name = "uio_ubicom32ring"; -+ -+/* -+ * The number of ring_tio's currently allocated, used for .id -+ */ -+static int __initdata ring_tio_count; -+ -+/* -+ * The maximum number of resources that the ring_tio will have. -+ * Currently 3, a register space, and up to 2 interrupts. -+ */ -+#define RING_TIO_MAX_RESOURCES 3 -+ -+/* -+ * ring_tio_init -+ * Checks the device tree and instantiates the driver if found -+ */ -+void __init ring_tio_init(const char *node_name) -+{ -+ struct platform_device *pdev; -+ struct resource *res; -+ int resource_idx = 0; -+ struct ring_tio_node *ring_node; -+ -+ /* -+ * Check the device tree for the ring_tio -+ */ -+ ring_node = (struct ring_tio_node *)devtree_find_node(node_name); -+ if (!ring_node) { -+ printk(KERN_WARNING "Ring TIO '%s' not found\n", node_name); -+ return; -+ } -+ -+ if (ring_node->version != RING_TIO_NODE_VERSION) { -+ printk(KERN_WARNING "ring_tio not compatible\n"); -+ return; -+ } -+ -+ /* -+ * Dynamically create the platform_device structure and resources -+ */ -+ pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); -+ if (!pdev) { -+ printk(KERN_WARNING "ring_tio could not alloc pdev\n"); -+ return; -+ } -+ -+ res = kzalloc(sizeof(struct resource) * RING_TIO_MAX_RESOURCES, -+ GFP_KERNEL); -+ if (!res) { -+ kfree(pdev); -+ printk(KERN_WARNING "ring_tio could not alloc res\n"); -+ return; -+ } -+ -+ pdev->name = ring_tio_driver_name; -+ pdev->id = ring_tio_count++; -+ pdev->resource = res; -+ -+ /* -+ * Fill in the resources and platform data from devtree information -+ */ -+ res[resource_idx].start = (u32_t)(ring_node->regs); -+ res[resource_idx].end = (u32_t)(ring_node->regs); -+ res[resource_idx].flags = IORESOURCE_MEM; -+ resource_idx++; -+ -+ if (ring_node->dn.sendirq != 0xFF) { -+ res[resource_idx].start = ring_node->dn.sendirq; -+ res[resource_idx].flags = IORESOURCE_IRQ; -+ resource_idx++; -+ } -+ -+ if (ring_node->dn.recvirq != 0xFF) { -+ res[resource_idx].start = ring_node->dn.recvirq; -+ res[resource_idx].flags = IORESOURCE_IRQ; -+ resource_idx++; -+ } -+ pdev->num_resources = resource_idx; -+ -+ printk(KERN_INFO "RingTIO.%d '%s' found irq=%d/%d regs=%p pdev=%p/%p\n", -+ ring_tio_count - 1, node_name, ring_node->dn.sendirq, -+ ring_node->dn.recvirq, ring_node->regs, pdev, res); -+ -+ /* -+ * Try to get the device registered -+ */ -+ pdev->dev.platform_data = (void *)node_name; -+ if (platform_device_register(pdev) < 0) { -+ printk(KERN_WARNING "Ring failed to register\n"); -+ kfree(pdev); -+ kfree(res); -+ } -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/switch-bcm539x.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/switch-bcm539x.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/switch-bcm539x.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/switch-bcm539x.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,1195 @@ -+/* -+ * arch/ubicom32/mach-common/switch-bcm539x.c -+ * BCM539X switch driver, SPI mode -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "switch-core.h" -+#include "switch-bcm539x-reg.h" -+ -+#define DRIVER_NAME "bcm539x-spi" -+#define DRIVER_VERSION "1.0" -+ -+#undef BCM539X_DEBUG -+#define BCM539X_SPI_RETRIES 100 -+ -+struct bcm539x_data { -+ struct switch_device *switch_dev; -+ -+ /* -+ * Our private data -+ */ -+ struct spi_device *spi; -+ struct switch_core_platform_data *pdata; -+ -+ /* -+ * Last page we accessed -+ */ -+ u8_t last_page; -+ -+ /* -+ * 539x Device ID -+ */ -+ u8_t device_id; -+}; -+ -+/* -+ * bcm539x_wait_status -+ * Waits for the specified bit in the status register to be set/cleared. -+ */ -+static int bcm539x_wait_status(struct bcm539x_data *bd, u8_t mask, int set) -+{ -+ u8_t txbuf[2]; -+ u8_t rxbuf; -+ int i; -+ int ret; -+ -+ txbuf[0] = BCM539X_CMD_READ; -+ txbuf[1] = BCM539X_GLOBAL_SPI_STATUS; -+ for (i = 0; i < BCM539X_SPI_RETRIES; i++) { -+ ret = spi_write_then_read(bd->spi, txbuf, 2, &rxbuf, 1); -+ rxbuf &= mask; -+ if ((set && rxbuf) || (!set && !rxbuf)) { -+ return 0; -+ } -+ udelay(1); -+ } -+ -+ return -EIO; -+} -+ -+/* -+ * bcm539x_set_page -+ * Sets the register page for access (only if necessary) -+ */ -+static int bcm539x_set_page(struct bcm539x_data *bd, u8_t page) -+{ -+ u8_t txbuf[3]; -+ -+ if (page == bd->last_page) { -+ return 0; -+ } -+ -+ bd->last_page = page; -+ -+ txbuf[0] = BCM539X_CMD_WRITE; -+ txbuf[1] = BCM539X_GLOBAL_PAGE; -+ txbuf[2] = page; -+ -+ return spi_write(bd->spi, txbuf, 3); -+} -+ -+/* -+ * bcm539x_write_bytes -+ * Writes a number of bytes to a given page and register -+ */ -+static int bcm539x_write_bytes(struct bcm539x_data *bd, u8_t page, -+ u8_t reg, void *buf, u8_t len) -+{ -+ int ret; -+ u8_t *txbuf; -+ -+ txbuf = kmalloc(2 + len, GFP_KERNEL); -+ if (!txbuf) { -+ return -ENOMEM; -+ } -+ -+ /* -+ * Make sure the chip has finished processing our previous request -+ */ -+ ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_SPIF, 0); -+ if (ret) { -+ goto done; -+ } -+ -+ /* -+ * Set the page -+ */ -+ ret = bcm539x_set_page(bd, page); -+ if (ret) { -+ goto done; -+ } -+ -+ /* -+ * Read the data -+ */ -+ txbuf[0] = BCM539X_CMD_WRITE; -+ txbuf[1] = reg; -+ memcpy(&txbuf[2], buf, len); -+ -+#ifdef BCM539X_DEBUG -+ { -+ int i; -+ printk("write page %02x reg %02x len=%d buf=", page, reg, len); -+ for (i = 0; i < len + 2; i++) { -+ printk("%02x ", txbuf[i]); -+ } -+ printk("\n"); -+ } -+#endif -+ -+ ret = spi_write(bd->spi, txbuf, 2 + len); -+ -+done: -+ kfree(txbuf); -+ return ret; -+} -+ -+/* -+ * bcm539x_write_32 -+ * Writes 32 bits of data to the given page and register -+ */ -+static inline int bcm539x_write_32(struct bcm539x_data *bd, u8_t page, -+ u8_t reg, u32_t data) -+{ -+ data = cpu_to_le32(data); -+ return bcm539x_write_bytes(bd, page, reg, &data, 4); -+} -+ -+/* -+ * bcm539x_write_16 -+ * Writes 16 bits of data to the given page and register -+ */ -+static inline int bcm539x_write_16(struct bcm539x_data *bd, u8_t page, -+ u8_t reg, u16_t data) -+{ -+ data = cpu_to_le16(data); -+ return bcm539x_write_bytes(bd, page, reg, &data, 2); -+} -+ -+/* -+ * bcm539x_write_8 -+ * Writes 8 bits of data to the given page and register -+ */ -+static inline int bcm539x_write_8(struct bcm539x_data *bd, u8_t page, -+ u8_t reg, u8_t data) -+{ -+ return bcm539x_write_bytes(bd, page, reg, &data, 1); -+} -+ -+/* -+ * bcm539x_read_bytes -+ * Reads a number of bytes from a given page and register -+ */ -+static int bcm539x_read_bytes(struct bcm539x_data *bd, u8_t page, -+ u8_t reg, void *buf, u8_t len) -+{ -+ u8_t txbuf[2]; -+ int ret; -+ -+ /* -+ * (1) Make sure the chip has finished processing our previous request -+ */ -+ ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_SPIF, 0); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * (2) Set the page -+ */ -+ ret = bcm539x_set_page(bd, page); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * (3) Kick off the register read -+ */ -+ txbuf[0] = BCM539X_CMD_READ; -+ txbuf[1] = reg; -+ ret = spi_write_then_read(bd->spi, txbuf, 2, txbuf, 1); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * (4) Wait for RACK -+ */ -+ ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_RACK, 1); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * (5) Read the data -+ */ -+ txbuf[0] = BCM539X_CMD_READ; -+ txbuf[1] = BCM539X_GLOBAL_SPI_DATA0; -+ -+ ret = spi_write_then_read(bd->spi, txbuf, 2, buf, len); -+ -+#ifdef BCM539X_DEBUG -+ { -+ int i; -+ printk("read page %02x reg %02x len=%d rxbuf=", -+ page, reg, len); -+ for (i = 0; i < len; i++) { -+ printk("%02x ", ((u8_t *)buf)[i]); -+ } -+ printk("\n"); -+ } -+#endif -+ -+ return ret; -+} -+ -+/* -+ * bcm539x_read_32 -+ * Reads an 32 bit number from a given page and register -+ */ -+static int bcm539x_read_32(struct bcm539x_data *bd, u8_t page, -+ u8_t reg, u32_t *buf) -+{ -+ int ret = bcm539x_read_bytes(bd, page, reg, buf, 4); -+ *buf = le32_to_cpu(*buf); -+ return ret; -+} -+ -+/* -+ * bcm539x_read_16 -+ * Reads an 16 bit number from a given page and register -+ */ -+static int bcm539x_read_16(struct bcm539x_data *bd, u8_t page, -+ u8_t reg, u16_t *buf) -+{ -+ int ret = bcm539x_read_bytes(bd, page, reg, buf, 2); -+ *buf = le16_to_cpu(*buf); -+ return ret; -+} -+ -+/* -+ * bcm539x_read_8 -+ * Reads an 8 bit number from a given page and register -+ */ -+static int bcm539x_read_8(struct bcm539x_data *bd, u8_t page, -+ u8_t reg, u8_t *buf) -+{ -+ return bcm539x_read_bytes(bd, page, reg, buf, 1); -+} -+ -+/* -+ * bcm539x_set_mode -+ */ -+static int bcm539x_set_mode(struct bcm539x_data *bd, int state) -+{ -+ u8_t buf; -+ int ret; -+ -+ ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, &buf); -+ if (ret) { -+ return ret; -+ } -+ -+ buf &= ~(1 << 1); -+ buf |= state ? (1 << 1) : 0; -+ -+ ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, buf); -+ return ret; -+} -+ -+/* -+ * bcm539x_handle_reset -+ */ -+static int bcm539x_handle_reset(struct switch_device *dev, char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ int ret; -+ -+ ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_SRST, -+ (1 << 7) | (1 << 4)); -+ if (ret) { -+ return ret; -+ } -+ -+ udelay(20); -+ -+ ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_SRST, 0); -+ return ret; -+} -+ -+/* -+ * bcm539x_handle_vlan_ports_read -+ */ -+static int bcm539x_handle_vlan_ports_read(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ int j; -+ int len = 0; -+ u8_t rxbuf8; -+ u32_t rxbuf32; -+ int ret; -+ -+ ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, inst); -+ if (ret) { -+ return ret; -+ } -+ -+ ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, -+ (1 << 7) | 1); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * Wait for completion -+ */ -+ for (j = 0; j < BCM539X_SPI_RETRIES; j++) { -+ ret = bcm539x_read_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, -+ &rxbuf8); -+ if (ret) { -+ return ret; -+ } -+ if (!(rxbuf8 & (1 << 7))) { -+ break; -+ } -+ } -+ -+ if (j == BCM539X_SPI_RETRIES) { -+ return -EIO; -+ } -+ -+ /* -+ * Read the table entry -+ */ -+ ret = bcm539x_read_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, &rxbuf32); -+ if (ret) { -+ return ret; -+ } -+ -+ for (j = 0; j < 9; j++) { -+ if (rxbuf32 & (1 << j)) { -+ u16_t rxbuf16; -+ len += sprintf(buf + len, "%d", j); -+ if (rxbuf32 & (1 << (j + 9))) { -+ buf[len++] = 'u'; -+ } else { -+ buf[len++] = 't'; -+ } -+ ret = bcm539x_read_16(bd, PAGE_VLAN, -+ REG_VLAN_PTAG0 + (j << 1), -+ &rxbuf16); -+ if (ret) { -+ return ret; -+ } -+ if (rxbuf16 == inst) { -+ buf[len++] = '*'; -+ } -+ buf[len++] = '\t'; -+ } -+ } -+ -+ len += sprintf(buf + len, "\n"); -+ buf[len] = '\0'; -+ -+ return len; -+} -+ -+/* -+ * bcm539x_handle_vlan_ports_write -+ */ -+static int bcm539x_handle_vlan_ports_write(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ int j; -+ u32_t untag; -+ u32_t ports; -+ u32_t def; -+ -+ u8_t rxbuf8; -+ u16_t rxbuf16; -+ int ret; -+ -+ switch_parse_vlan_ports(dev, buf, &untag, &ports, &def); -+ -+#ifdef BCM539X_DEBUG -+ printk(KERN_DEBUG "'%s' inst=%d untag=%08x ports=%08x def=%08x\n", -+ buf, inst, untag, ports, def); -+#endif -+ -+ if (!ports) { -+ return 0; -+ } -+ -+ /* -+ * Change default vlan tag -+ */ -+ for (j = 0; j < 9; j++) { -+ if ((untag | def) & (1 << j)) { -+ ret = bcm539x_write_16(bd, PAGE_VLAN, -+ REG_VLAN_PTAG0 + (j << 1), -+ inst); -+ if (ret) { -+ return ret; -+ } -+ continue; -+ } -+ -+ if (!(dev->port_mask[0] & (1 << j))) { -+ continue; -+ } -+ -+ /* -+ * Remove any ports which are not listed anymore as members of -+ * this vlan -+ */ -+ ret = bcm539x_read_16(bd, PAGE_VLAN, -+ REG_VLAN_PTAG0 + (j << 1), &rxbuf16); -+ if (ret) { -+ return ret; -+ } -+ if (rxbuf16 == inst) { -+ ret = bcm539x_write_16(bd, PAGE_VLAN, -+ REG_VLAN_PTAG0 + (j << 1), 0); -+ if (ret) { -+ return ret; -+ } -+ } -+ } -+ -+ /* -+ * Write the VLAN table -+ */ -+ ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, inst); -+ if (ret) { -+ return ret; -+ } -+ -+ ret = bcm539x_write_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, -+ (untag << 9) | ports); -+ if (ret) { -+ return ret; -+ } -+ -+ ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, -+ (1 << 7) | 0); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * Wait for completion -+ */ -+ for (j = 0; j < BCM539X_SPI_RETRIES; j++) { -+ ret = bcm539x_read_bytes(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, -+ &rxbuf8, 1); -+ if (ret) { -+ return ret; -+ } -+ if (!(rxbuf8 & (1 << 7))) { -+ break; -+ } -+ } -+ -+ return (j < BCM539X_SPI_RETRIES) ? 0 : -EIO; -+} -+ -+/* -+ * Handlers for /vlan/ -+ */ -+static const struct switch_handler bcm539x_switch_handlers_vlan_dir[] = { -+ { -+ .name = "ports", -+ .read = bcm539x_handle_vlan_ports_read, -+ .write = bcm539x_handle_vlan_ports_write, -+ }, -+ { -+ }, -+}; -+ -+/* -+ * bcm539x_handle_vlan_delete_write -+ */ -+static int bcm539x_handle_vlan_delete_write(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ int vid; -+ u8_t rxbuf8; -+ u32_t txbuf; -+ int j; -+ int ret; -+ -+ vid = simple_strtoul(buf, NULL, 0); -+ if (!vid) { -+ return -EINVAL; -+ } -+ -+ /* -+ * Disable this VLAN -+ * -+ * Go through the port-based vlan registers and clear the appropriate -+ * ones out -+ */ -+ for (j = 0; j < 9; j++) { -+ u16_t rxbuf16; -+ ret = bcm539x_read_16(bd, PAGE_VLAN, REG_VLAN_PTAG0 + (j << 1), -+ &rxbuf16); -+ if (ret) { -+ return ret; -+ } -+ if (rxbuf16 == vid) { -+ txbuf = 0; -+ ret = bcm539x_write_16(bd, PAGE_VLAN, -+ REG_VLAN_PTAG0 + (j << 1), -+ txbuf); -+ if (ret) { -+ return ret; -+ } -+ } -+ } -+ -+ /* -+ * Write the VLAN table -+ */ -+ txbuf = vid; -+ ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, txbuf); -+ if (ret) { -+ return ret; -+ } -+ -+ txbuf = 0; -+ ret = bcm539x_write_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, txbuf); -+ if (ret) { -+ return ret; -+ } -+ -+ txbuf = (1 << 7) | (0); -+ ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, txbuf); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * Wait for completion -+ */ -+ for (j = 0; j < BCM539X_SPI_RETRIES; j++) { -+ ret = bcm539x_read_bytes(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, -+ &rxbuf8, 1); -+ if (ret) { -+ return ret; -+ } -+ if (!(rxbuf8 & (1 << 7))) { -+ break; -+ } -+ } -+ -+ if (j == BCM539X_SPI_RETRIES) { -+ return -EIO; -+ } -+ -+ return switch_remove_vlan_dir(dev, vid); -+} -+ -+/* -+ * bcm539x_handle_vlan_create_write -+ */ -+static int bcm539x_handle_vlan_create_write(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ int vid; -+ -+ vid = simple_strtoul(buf, NULL, 0); -+ if (!vid) { -+ return -EINVAL; -+ } -+ -+ return switch_create_vlan_dir(dev, vid, -+ bcm539x_switch_handlers_vlan_dir); -+} -+ -+/* -+ * bcm539x_handle_enable_read -+ */ -+static int bcm539x_handle_enable_read(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ u8_t rxbuf; -+ int ret; -+ -+ ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, &rxbuf); -+ if (ret) { -+ return ret; -+ } -+ rxbuf = (rxbuf & (1 << 1)) ? 1 : 0; -+ -+ return sprintf(buf, "%d\n", rxbuf); -+} -+ -+/* -+ * bcm539x_handle_enable_write -+ */ -+static int bcm539x_handle_enable_write(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ -+ return bcm539x_set_mode(bd, buf[0] == '1'); -+} -+ -+/* -+ * bcm539x_handle_enable_vlan_read -+ */ -+static int bcm539x_handle_enable_vlan_read(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ u8_t rxbuf; -+ int ret; -+ -+ ret = bcm539x_read_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, &rxbuf); -+ if (ret) { -+ return ret; -+ } -+ rxbuf = (rxbuf & (1 << 7)) ? 1 : 0; -+ -+ return sprintf(buf, "%d\n", rxbuf); -+} -+ -+/* -+ * bcm539x_handle_enable_vlan_write -+ */ -+static int bcm539x_handle_enable_vlan_write(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ int ret; -+ -+ /* -+ * disable 802.1Q VLANs -+ */ -+ if (buf[0] != '1') { -+ ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, 0); -+ return ret; -+ } -+ -+ /* -+ * enable 802.1Q VLANs -+ * -+ * Enable 802.1Q | IVL learning -+ */ -+ ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, -+ (1 << 7) | (3 << 5)); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * RSV multicast fwd | RSV multicast chk -+ */ -+ ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL1, -+ (1 << 2) | (1 << 3)); -+ if (ret) { -+ return ret; -+ } -+#if 0 -+ /* -+ * Drop invalid VID -+ */ -+ ret = bcm539x_write_16(bd, PAGE_VLAN, REG_VLAN_CTRL3, 0x00FF); -+ if (ret) { -+ return ret; -+ } -+#endif -+ return 0; -+} -+ -+/* -+ * bcm539x_handle_port_enable_read -+ */ -+static int bcm539x_handle_port_enable_read(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ return sprintf(buf, "%d\n", 1); -+} -+ -+/* -+ * bcm539x_handle_port_enable_write -+ */ -+static int bcm539x_handle_port_enable_write(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ /* -+ * validate port -+ */ -+ if (!(dev->port_mask[0] & (1 << inst))) { -+ return -EIO; -+ } -+ -+ if (buf[0] != '1') { -+ printk(KERN_WARNING "switch port[%d] disabling is not supported\n", inst); -+ } -+ return 0; -+} -+ -+/* -+ * bcm539x_handle_port_state_read -+ */ -+static int bcm539x_handle_port_state_read(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ int ret; -+ u16_t link; -+ -+ /* -+ * validate port -+ */ -+ if (!(dev->port_mask[0] & (1 << inst))) { -+ return -EIO; -+ } -+ -+ /* -+ * check PHY link state - CPU port (port 8) is always up -+ */ -+ ret = bcm539x_read_16(bd, PAGE_STATUS, REG_LINK_STATUS, &link); -+ if (ret) { -+ return ret; -+ } -+ link |= (1 << 8); -+ -+ return sprintf(buf, "%d\n", (link & (1 << inst)) ? 1 : 0); -+} -+ -+/* -+ * bcm539x_handle_port_media_read -+ */ -+static int bcm539x_handle_port_media_read(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ int ret; -+ u16_t link, duplex; -+ u32_t speed; -+ -+ /* -+ * validate port -+ */ -+ if (!(dev->port_mask[0] & (1 << inst))) { -+ return -EIO; -+ } -+ -+ /* -+ * check PHY link state first - CPU port (port 8) is always up -+ */ -+ ret = bcm539x_read_16(bd, PAGE_STATUS, REG_LINK_STATUS, &link); -+ if (ret) { -+ return ret; -+ } -+ link |= (1 << 8); -+ -+ if (!(link & (1 << inst))) { -+ return sprintf(buf, "UNKNOWN\n"); -+ } -+ -+ /* -+ * get link speeda dn duplex - CPU port (port 8) is 1000/full -+ */ -+ ret = bcm539x_read_32(bd, PAGE_STATUS, 4, &speed); -+ if (ret) { -+ return ret; -+ } -+ speed |= (2 << 16); -+ speed = (speed >> (2 * inst)) & 3; -+ -+ ret = bcm539x_read_16(bd, PAGE_STATUS, 8, &duplex); -+ if (ret) { -+ return ret; -+ } -+ duplex |= (1 << 8); -+ duplex = (duplex >> inst) & 1; -+ -+ return sprintf(buf, "%d%cD\n", -+ (speed == 0) ? 10 : ((speed == 1) ? 100 : 1000), -+ duplex ? 'F' : 'H'); -+} -+ -+/* -+ * bcm539x_handle_port_meida_write -+ */ -+static int bcm539x_handle_port_meida_write(struct switch_device *dev, -+ char *buf, int inst) -+{ -+ struct bcm539x_data *bd = -+ (struct bcm539x_data *)switch_get_drvdata(dev); -+ int ret; -+ u16_t ctrl_word, local_cap, local_giga_cap; -+ -+ /* -+ * validate port (not for CPU port) -+ */ -+ if (!(dev->port_mask[0] & (1 << inst) & ~(1 << 8))) { -+ return -EIO; -+ } -+ -+ /* -+ * Get the maximum capability from status -+ * SPI reg[0x00] = PHY[0x0] --- MII control -+ * SPI reg[0x08] = PHY[0x4] --- MII local capability -+ * SPI reg[0x12] = PHY[0x9] --- GMII control -+ */ -+ ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_ADVERTISE << 1), &local_cap); -+ if (ret) { -+ return ret; -+ } -+ ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_CTRL1000 << 1), &local_giga_cap); -+ if (ret) { -+ return ret; -+ } -+ -+ /* Configure to the requested speed */ -+ if (strncmp(buf, "1000FD", 6) == 0) { -+ /* speed */ -+ local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL); -+ local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL); -+ local_giga_cap |= (ADVERTISE_1000HALF | ADVERTISE_1000FULL); -+ /* duplex */ -+ } else if (strncmp(buf, "100FD", 5) == 0) { -+ /* speed */ -+ local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL); -+ local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL); -+ local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); -+ /* duplex */ -+ local_cap &= ~(ADVERTISE_100HALF); -+ } else if (strncmp(buf, "100HD", 5) == 0) { -+ /* speed */ -+ local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL); -+ local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL); -+ local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); -+ /* duplex */ -+ local_cap &= ~(ADVERTISE_100FULL); -+ } else if (strncmp(buf, "10FD", 4) == 0) { -+ /* speed */ -+ local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL); -+ local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL); -+ local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); -+ /* duplex */ -+ local_cap &= ~(ADVERTISE_10HALF); -+ } else if (strncmp(buf, "10HD", 4) == 0) { -+ /* speed */ -+ local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL); -+ local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL); -+ local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); -+ /* duplex */ -+ local_cap &= ~(ADVERTISE_10FULL); -+ } else if (strncmp(buf, "AUTO", 4) == 0) { -+ /* speed */ -+ local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL); -+ local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL); -+ local_giga_cap |= (ADVERTISE_1000HALF | ADVERTISE_1000FULL); -+ } else { -+ return -EINVAL; -+ } -+ -+ /* Active PHY with the requested speed for auto-negotiation */ -+ ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_ADVERTISE << 1), local_cap); -+ if (ret) { -+ return ret; -+ } -+ ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_CTRL1000 << 1), local_giga_cap); -+ if (ret) { -+ return ret; -+ } -+ -+ ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_BMCR << 1), &ctrl_word); -+ if (ret) { -+ return ret; -+ } -+ ctrl_word |= (BMCR_ANENABLE | BMCR_ANRESTART); -+ ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_BMCR << 1), ctrl_word); -+ if (ret) { -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* -+ * proc_fs entries for this switch -+ */ -+static const struct switch_handler bcm539x_switch_handlers[] = { -+ { -+ .name = "enable", -+ .read = bcm539x_handle_enable_read, -+ .write = bcm539x_handle_enable_write, -+ }, -+ { -+ .name = "enable_vlan", -+ .read = bcm539x_handle_enable_vlan_read, -+ .write = bcm539x_handle_enable_vlan_write, -+ }, -+ { -+ .name = "reset", -+ .write = bcm539x_handle_reset, -+ }, -+ { -+ }, -+}; -+ -+/* -+ * Handlers for /vlan -+ */ -+static const struct switch_handler bcm539x_switch_handlers_vlan[] = { -+ { -+ .name = "delete", -+ .write = bcm539x_handle_vlan_delete_write, -+ }, -+ { -+ .name = "create", -+ .write = bcm539x_handle_vlan_create_write, -+ }, -+ { -+ }, -+}; -+ -+/* -+ * Handlers for /port/ -+ */ -+static const struct switch_handler bcm539x_switch_handlers_port[] = { -+ { -+ .name = "enable", -+ .read = bcm539x_handle_port_enable_read, -+ .write = bcm539x_handle_port_enable_write, -+ }, -+ { -+ .name = "state", -+ .read = bcm539x_handle_port_state_read, -+ }, -+ { -+ .name = "media", -+ .read = bcm539x_handle_port_media_read, -+ .write = bcm539x_handle_port_meida_write, -+ }, -+ { -+ }, -+}; -+ -+/* -+ * bcm539x_probe -+ */ -+static int __devinit bcm539x_probe(struct spi_device *spi) -+{ -+ struct bcm539x_data *bd; -+ struct switch_core_platform_data *pdata; -+ struct switch_device *switch_dev = NULL; -+ int i, ret; -+ u8_t txbuf[2]; -+ -+ pdata = spi->dev.platform_data; -+ if (!pdata) { -+ return -EINVAL; -+ } -+ -+ ret = spi_setup(spi); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ /* -+ * Reset the chip if requested -+ */ -+ if (pdata->flags & SWITCH_DEV_FLAG_HW_RESET) { -+ ret = gpio_request(pdata->pin_reset, "switch-bcm539x-reset"); -+ if (ret) { -+ printk(KERN_WARNING "Could not request reset\n"); -+ return -EINVAL; -+ } -+ -+ gpio_direction_output(pdata->pin_reset, 0); -+ udelay(10); -+ gpio_set_value(pdata->pin_reset, 1); -+ udelay(20); -+ } -+ -+ /* -+ * Allocate our private data structure -+ */ -+ bd = kzalloc(sizeof(struct bcm539x_data), GFP_KERNEL); -+ if (!bd) { -+ return -ENOMEM; -+ } -+ -+ dev_set_drvdata(&spi->dev, bd); -+ bd->pdata = pdata; -+ bd->spi = spi; -+ bd->last_page = 0xFF; -+ -+ /* -+ * First perform SW reset if needed -+ */ -+ if (pdata->flags & SWITCH_DEV_FLAG_SW_RESET) { -+ txbuf[0] = (1 << 7) | (1 << 4); -+ ret = bcm539x_write_bytes(bd, PAGE_PORT_TC, -+ REG_CTRL_SRST, txbuf, 1); -+ if (ret) { -+ goto fail; -+ } -+ -+ udelay(20); -+ -+ txbuf[0] = 0; -+ ret = bcm539x_write_bytes(bd, PAGE_PORT_TC, -+ REG_CTRL_SRST, txbuf, 1); -+ if (ret) { -+ goto fail; -+ } -+ } -+ -+ /* -+ * See if we can see the chip -+ */ -+ for (i = 0; i < 10; i++) { -+ ret = bcm539x_read_bytes(bd, PAGE_MMR, REG_DEVICE_ID, -+ &bd->device_id, 1); -+ if (!ret) { -+ break; -+ } -+ } -+ if (ret) { -+ goto fail; -+ } -+ -+ /* -+ * We only support 5395, 5397, 5398 -+ */ -+ if ((bd->device_id != 0x95) && (bd->device_id != 0x97) && -+ (bd->device_id != 0x98)) { -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ /* -+ * Override CPU port config: fixed link @1000 with flow control -+ */ -+ ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MIIPO, txbuf); -+ bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_MIIPO, 0xbb); // Override IMP port config -+ printk("Broadcom SW CPU port setting: 0x%x -> 0xbb\n", txbuf[0]); -+ -+ /* -+ * Setup the switch driver structure -+ */ -+ switch_dev = switch_alloc(); -+ if (!switch_dev) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ switch_dev->name = pdata->name; -+ -+ switch_dev->ports = (bd->device_id == 0x98) ? 9 : 6; -+ switch_dev->port_mask[0] = (bd->device_id == 0x98) ? 0x1FF : 0x11F; -+ switch_dev->driver_handlers = bcm539x_switch_handlers; -+ switch_dev->reg_handlers = NULL; -+ switch_dev->vlan_handlers = bcm539x_switch_handlers_vlan; -+ switch_dev->port_handlers = bcm539x_switch_handlers_port; -+ -+ bd->switch_dev = switch_dev; -+ switch_set_drvdata(switch_dev, (void *)bd); -+ -+ ret = switch_register(bd->switch_dev); -+ if (ret < 0) { -+ goto fail; -+ } -+ -+ printk(KERN_INFO "bcm53%02x switch chip initialized\n", bd->device_id); -+ -+ return ret; -+ -+fail: -+ if (switch_dev) { -+ switch_release(switch_dev); -+ } -+ dev_set_drvdata(&spi->dev, NULL); -+ kfree(bd); -+ return ret; -+} -+ -+static int __attribute__((unused)) bcm539x_remove(struct spi_device *spi) -+{ -+ struct bcm539x_data *bd; -+ -+ bd = dev_get_drvdata(&spi->dev); -+ -+ if (bd->pdata->flags & SWITCH_DEV_FLAG_HW_RESET) { -+ gpio_free(bd->pdata->pin_reset); -+ } -+ -+ if (bd->switch_dev) { -+ switch_unregister(bd->switch_dev); -+ switch_release(bd->switch_dev); -+ } -+ -+ dev_set_drvdata(&spi->dev, NULL); -+ -+ kfree(bd); -+ -+ return 0; -+} -+ -+static struct spi_driver bcm539x_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ .probe = bcm539x_probe, -+ .remove = __devexit_p(bcm539x_remove), -+}; -+ -+static int __init bcm539x_init(void) -+{ -+ return spi_register_driver(&bcm539x_driver); -+} -+ -+module_init(bcm539x_init); -+ -+static void __exit bcm539x_exit(void) -+{ -+ spi_unregister_driver(&bcm539x_driver); -+} -+module_exit(bcm539x_exit); -+ -+MODULE_AUTHOR("Pat Tjin"); -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION("bcm539x SPI switch chip driver"); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/switch-bcm539x-reg.h linux-2.6.30.10-ubi/arch/ubicom32/mach-common/switch-bcm539x-reg.h ---- linux-2.6.30.10/arch/ubicom32/mach-common/switch-bcm539x-reg.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/switch-bcm539x-reg.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,221 @@ -+/* -+ * arch/ubicom32/mach-common/switch-bcm539x-reg.h -+ * Broadcom switch definitions for Ubicom32 architecture. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+/* -+ * Broadcom 53xx RoboSwitch device driver. -+ * -+ * Copyright 2007, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ * $Id$ -+ */ -+ -+#ifndef _SWITCH_BCM539X_REG_H_ -+#define _SWITCH_BCM539X_REG_H_ -+ -+#define BCM539X_CMD_READ 0x60 -+#define BCM539X_CMD_WRITE 0x61 -+ -+#define BCM539X_GLOBAL_SPI_DATA0 0xf0 -+ -+#define BCM539X_GLOBAL_SPI_STATUS 0xfe -+#define BCM539X_GLOBAL_SPI_ST_SPIF (1<<7) -+#define BCM539X_GLOBAL_SPI_ST_RACK (1<<5) -+ -+#define BCM539X_GLOBAL_PAGE 0xff -+ -+#define PAGE_PORT_TC 0x00 // Port Traffic Control Register -+ -+#define PAGE_QOS_CTL 0x30 // QoS Global Control Register -+#define PAGE_QOS_TAG 0x34 // Default IEEE 802.1Q TAG Register -+ -+#define PAGE_MII_CTL_PORT0 0x10 // Internal PHY MII Register -+#define PAGE_MII_CTL_PORT1 0x11 -+#define PAGE_MII_CTL_PORT2 0x12 -+#define PAGE_MII_CTL_PORT3 0x13 -+#define PAGE_MII_CTL_PORT4 0x14 -+ -+#define PAGE_STATUS 0x01 // Status Register Page -+#define PAGE_RATE_CONTROL 0x41 // Broadcast Storm Suppression Register -+ -+#define REG_GRATE_CONTROL 0x00 -+ -+#define REG_LED_POWER 0x12 -+ -+// Ingress Rate Control -+#define REG_IRATE_CONTROLP0 0x10 -+#define REG_IRATE_CONTROLP1 0x14 -+#define REG_IRATE_CONTROLP2 0x18 -+#define REG_IRATE_CONTROLP3 0x1C -+#define REG_IRATE_CONTROLP4 0x20 -+#define REG_IRATE_CONTROLP7 0x2C -+#define REG_IRATE_CONTROLPI 0x30 -+ -+// Egress Rate Control -+#define REG_ERATE_CONTROLP0 0x80 -+#define REG_ERATE_CONTROLP1 0x82 -+#define REG_ERATE_CONTROLP2 0x84 -+#define REG_ERATE_CONTROLP3 0x86 -+#define REG_ERATE_CONTROLP4 0x88 -+#define REG_ERATE_CONTROLP5 0x8A -+#define REG_ERATE_CONTROLP6 0x8C -+#define REG_ERATE_CONTROLP7 0x8E -+#define REG_ERATE_CONTROLPI 0x90 -+ -+#define REG_LINK_STATUS 0x00 -+ -+#define REG_TC_PORT0 0x00 -+#define REG_TC_PORT1 0x01 -+#define REG_TC_PORT2 0x02 -+#define REG_TC_PORT3 0x03 -+#define REG_TC_PORT4 0x04 -+#define REG_TC_PORT5 0x05 -+ -+#define REG_SPEED_CTL 0x00 -+#define REG_SPEED_ADV100 0x08 -+#define REG_SPEED_ADV1000 0x12 -+ -+#define REG_QOS_EN 0x00 -+#define REG_QOS_TAG_PORT1 0x12 // Default IEEE 802.1Q TAG, PORT 1 -+#define REG_QOS_TAG_PORT2 0x14 // Default IEEE 802.1Q TAG, PORT 2 -+#define REG_QOS_TAG_PORT3 0x16 // Default IEEE 802.1Q TAG, PORT 3 -+#define REG_QOS_TAG_PORT4 0x18 // Default IEEE 802.1Q TAG, PORT 4 -+#define REG_QOS_PID_PORT1 0x52 // Ingress Port Priority ID MAP, PORT 1 -+#define REG_QOS_PID_PORT2 0x54 // Ingress Port Priority ID MAP, PORT 2 -+#define REG_QOS_PID_PORT3 0x56 // Ingress Port Priority ID MAP, PORT 3 -+#define REG_QOS_PID_PORT4 0x58 // Ingress Port Priority ID MAP, PORT 4 -+#define REG_QOS_TXQ_CTL 0x80 // Tx Queue Control Register -+#define REG_QOS_TXQ_WHTQ0 0x81 // Tx Queue Weight Register Queue 0 -+#define REG_QOS_TXQ_WHTQ1 0x82 // Tx Queue Weight Register Queue 1 -+#define REG_QOS_TXQ_WHTQ2 0x83 // Tx Queue Weight Register Queue 2 -+#define REG_QOS_TXQ_WHTQ3 0x84 // Tx Queue Weight Register Queue 3 -+ -+#define REG_CTRL_PPSEL 0x24 /* 5397: Protected port select register */ -+ -+#define RATE_CONTROL_ENABLED (1 << 22) -+#define RATE_CONTROL_BSIZE ((1 << 10) | (1 << 9) | (1 << 8)) -+ -+#define RATE_CONTROL_HIGH ((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4)) -+#define RATE_CONTROL_HIGH_N ~((1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)) -+ -+#define RATE_CONTROL_MEDIUM ((1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)) -+#define RATE_CONTROL_MEDIUM_N ~((1 << 7)) -+ -+#define RATE_CONTROL_NORMAL ((1 << 5) | (1 << 2) | (1 << 0)) -+#define RATE_CONTROL_NORMAL_N ~((1 << 7) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1)) -+ -+#define RATE_CONTROL_LOW ((1 << 4) | (1 << 3) | (1 << 0)) -+#define RATE_CONTROL_LOW_N ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2) | (1 << 1)) -+ -+// --- Gemtek, Configure the switch to support Ethernet Port QoS -+ -+/* MII access registers */ -+#define PSEUDO_PHYAD 0x1E /* MII Pseudo PHY address */ -+#define REG_MII_PAGE 0x10 /* MII Page register */ -+#define REG_MII_ADDR 0x11 /* MII Address register */ -+#define REG_MII_DATA0 0x18 /* MII Data register 0 */ -+#define REG_MII_DATA1 0x19 /* MII Data register 1 */ -+#define REG_MII_DATA2 0x1a /* MII Data register 2 */ -+#define REG_MII_DATA3 0x1b /* MII Data register 3 */ -+ -+/* Page numbers */ -+#define PAGE_CTRL 0x00 /* Control page */ -+#define PAGE_MMR 0x02 /* 5397 Management/Mirroring page */ -+#define PAGE_VTBL 0x05 /* ARL/VLAN Table access page */ -+#define PAGE_VLAN 0x34 /* VLAN page */ -+ -+/* Control page registers */ -+#define REG_CTRL_PORT0 0x00 /* Port 0 traffic control register */ -+#define REG_CTRL_PORT1 0x01 /* Port 1 traffic control register */ -+#define REG_CTRL_PORT2 0x02 /* Port 2 traffic control register */ -+#define REG_CTRL_PORT3 0x03 /* Port 3 traffic control register */ -+#define REG_CTRL_PORT4 0x04 /* Port 4 traffic control register */ -+#define REG_CTRL_PORT5 0x05 /* Port 5 traffic control register */ -+#define REG_CTRL_PORT6 0x06 /* Port 6 traffic control register */ -+#define REG_CTRL_PORT7 0x07 /* Port 7 traffic control register */ -+#define REG_CTRL_MODE 0x0B /* Switch Mode register */ -+#define REG_CTRL_MIIPO 0x0E /* 5325: MII Port Override register */ -+#define REG_CTRL_SRST 0x79 /* Software reset control register */ -+ -+#define REG_DEVICE_ID 0x30 /* 539x Device id: */ -+#define DEVID5395 0x95 /* 5395 */ -+#define DEVID5397 0x97 /* 5397 */ -+#define DEVID5398 0x98 /* 5398 */ -+#define REG_REVISION_ID 0x40 /* 539x Revision id: */ -+ -+/* VLAN page registers */ -+#define REG_VLAN_CTRL0 0x00 /* VLAN Control 0 register */ -+#define REG_VLAN_CTRL1 0x01 /* VLAN Control 1 register */ -+#define REG_VLAN_CTRL2 0x02 /* VLAN Control 2 register */ -+#define REG_VLAN_CTRL3 0x03 /* VLAN Control 3 register */ -+#define REG_VLAN_CTRL4 0x04 /* VLAN Control 4 register */ -+#define REG_VLAN_CTRL5 0x05 /* VLAN Control 5 register */ -+#define REG_VLAN_ACCESS 0x06 /* VLAN Table Access register */ -+#define REG_VLAN_WRITE 0x08 /* VLAN Write register */ -+#define REG_VLAN_READ 0x0C /* VLAN Read register */ -+#define REG_VLAN_PTAG0 0x10 /* VLAN Default Port Tag register - port 0 */ -+#define REG_VLAN_PTAG1 0x12 /* VLAN Default Port Tag register - port 1 */ -+#define REG_VLAN_PTAG2 0x14 /* VLAN Default Port Tag register - port 2 */ -+#define REG_VLAN_PTAG3 0x16 /* VLAN Default Port Tag register - port 3 */ -+#define REG_VLAN_PTAG4 0x18 /* VLAN Default Port Tag register - port 4 */ -+#define REG_VLAN_PTAG5 0x1a /* VLAN Default Port Tag register - port 5 */ -+#define REG_VLAN_PTAG6 0x1c /* VLAN Default Port Tag register - port 6 */ -+#define REG_VLAN_PTAG7 0x1e /* VLAN Default Port Tag register - port 7 */ -+#define REG_VLAN_PTAG8 0x20 /* 539x: VLAN Default Port Tag register - IMP port */ -+#define REG_VLAN_PMAP 0x20 /* 5325: VLAN Priority Re-map register */ -+ -+/* ARL/VLAN Table Access page registers */ -+#define REG_VTBL_CTRL 0x00 /* ARL Read/Write Control */ -+#define REG_VTBL_MINDX 0x02 /* MAC Address Index */ -+#define REG_VTBL_VINDX 0x08 /* VID Table Index */ -+#define REG_VTBL_ARL_E0 0x10 /* ARL Entry 0 */ -+#define REG_VTBL_ARL_E1 0x18 /* ARL Entry 1 */ -+#define REG_VTBL_DAT_E0 0x18 /* ARL Table Data Entry 0 */ -+#define REG_VTBL_SCTRL 0x20 /* ARL Search Control */ -+#define REG_VTBL_SADDR 0x22 /* ARL Search Address */ -+#define REG_VTBL_SRES 0x24 /* ARL Search Result */ -+#define REG_VTBL_SREXT 0x2c /* ARL Search Result */ -+#define REG_VTBL_VID_E0 0x30 /* VID Entry 0 */ -+#define REG_VTBL_VID_E1 0x32 /* VID Entry 1 */ -+#define REG_VTBL_PREG 0xFF /* Page Register */ -+#define REG_VTBL_ACCESS 0x60 /* VLAN table access register */ -+#define REG_VTBL_INDX 0x61 /* VLAN table address index register */ -+#define REG_VTBL_ENTRY 0x63 /* VLAN table entry register */ -+#define REG_VTBL_ACCESS_5395 0x80 /* VLAN table access register */ -+#define REG_VTBL_INDX_5395 0x81 /* VLAN table address index register */ -+#define REG_VTBL_ENTRY_5395 0x83 /* VLAN table entry register */ -+ -+/* SPI registers */ -+#define REG_SPI_PAGE 0xff /* SPI Page register */ -+ -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/switch-core.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/switch-core.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/switch-core.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/switch-core.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,737 @@ -+/* -+ * arch/ubicom32/mach-common/switch-core.c -+ * Ubicom32 architecture switch and /proc/switch/... implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2005 Felix Fietkau -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * -+ * Basic doc of driver's /proc interface: -+ * /proc/switch// -+ * registers: read-only -+ * counters: read-only -+ * reset: write causes hardware reset -+ * enable: "0", "1" -+ * enable_vlan: "0", "1" -+ * port// -+ * enabled: "0", "1" -+ * link state: read-only -+ * media: "AUTO", "1000FD", "100FD", "100HD", "10FD", "10HD" -+ * vlan// -+ * ports: same syntax as for nvram's vlan*ports (eg. "1 2 3 4 5*") -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "switch-core.h" -+ -+/* -+ * Pointer to the root of our filesystem -+ */ -+static struct proc_dir_entry *switch_root; -+ -+/* -+ * Lock used to manage access to the switch list -+ */ -+DECLARE_RWSEM(switch_list_lock); -+EXPORT_SYMBOL_GPL(switch_list_lock); -+ -+/* -+ * List of switches we are managing -+ */ -+LIST_HEAD(switch_list); -+EXPORT_SYMBOL_GPL(switch_list); -+ -+/* -+ * List of handlers we have -+ */ -+LIST_HEAD(switch_handler_list); -+EXPORT_SYMBOL_GPL(switch_handler_list); -+ -+/* -+ * Keep track of all the handlers we added -+ */ -+struct switch_handler_entry { -+ struct list_head node; -+ struct proc_dir_entry *parent; -+ struct switch_device *dev; -+ const struct switch_handler *handler; -+ int inst; -+}; -+ -+/* -+ * Keep track of all VLAN dirs we created -+ */ -+struct switch_vlan_entry { -+ struct list_head node; -+ struct proc_dir_entry *pde; -+ int vlan_id; -+ const struct switch_handler *handlers; -+}; -+ -+/* -+ * switch_parse_vlan_ports -+ * Parse the vlan properties written to /vlan//ports -+ */ -+void switch_parse_vlan_ports(struct switch_device *switch_dev, -+ char *buf, u32_t *untag, -+ u32_t *ports, u32_t *def) -+{ -+ u32_t tag = 0; -+ *untag = 0; -+ *ports = 0; -+ *def = 0; -+ -+ -+ /* -+ * Skip any leading spaces -+ */ -+ while (isspace(*buf)) { -+ buf++; -+ } -+ -+ /* -+ * Parse out the string -+ */ -+ while (*buf) { -+ u32_t port = simple_strtoul(buf, &buf, 10); -+ u32_t mask = (1 << port); -+ -+ /* -+ * Parse out any flags -+ */ -+ while (*buf && !isspace(*buf)) { -+ switch (*buf++) { -+ case 't': -+ tag |= mask; -+ break; -+ case '*': -+ *def |= mask; -+ break; -+ } -+ } -+ *ports |= mask; -+ -+ /* -+ * Skip any spaces -+ */ -+ while (isspace(*buf)) { -+ buf++; -+ } -+ } -+ -+ *untag = ~tag & *ports; -+} -+ -+/* -+ * switch_proc_read -+ * Handle reads from the procfs, dispatches the driver specific handler -+ */ -+static ssize_t switch_proc_read(struct file *file, char *buf, size_t count, -+ loff_t *ppos) -+{ -+ struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode); -+ char *page; -+ int len = 0; -+ -+ page = kmalloc(SWITCH_MAX_BUFSZ, GFP_KERNEL); -+ if (!page) { -+ return -ENOBUFS; -+ } -+ -+ if (pde->data != NULL) { -+ struct switch_handler_entry *she = -+ (struct switch_handler_entry *)pde->data; -+ if (she->handler->read) { -+ len += she->handler->read(she->dev, page + len, -+ she->inst); -+ } -+ } -+ len += 1; -+ -+ if (*ppos < len) { -+ len = min_t(int, len - *ppos, count); -+ if (copy_to_user(buf, (page + *ppos), len)) { -+ kfree(page); -+ return -EFAULT; -+ } -+ *ppos += len; -+ } else { -+ len = 0; -+ } -+ -+ kfree(page); -+ -+ return len; -+} -+ -+/* -+ * switch_proc_write -+ * Handle writes from the procfs, dispatches the driver specific handler -+ */ -+static ssize_t switch_proc_write(struct file *file, const char *buf, -+ size_t count, loff_t *data) -+{ -+ struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode); -+ char *page; -+ int ret = -EINVAL; -+ -+ page = kmalloc(count + 1, GFP_KERNEL); -+ if (page == NULL) -+ return -ENOBUFS; -+ -+ if (copy_from_user(page, buf, count)) { -+ kfree(page); -+ return -EINVAL; -+ } -+ page[count] = 0; -+ -+ if (pde->data != NULL) { -+ struct switch_handler_entry *she = -+ (struct switch_handler_entry *)pde->data; -+ if (she->handler->write) { -+ ret = she->handler->write(she->dev, page, she->inst); -+ if (ret >= 0) { -+ ret = count; -+ } -+ } -+ } -+ -+ kfree(page); -+ return ret; -+} -+ -+/* -+ * File operations for the proc_fs, we must cast here since proc_fs' definitions -+ * differ from file_operations definitions. -+ */ -+static struct file_operations switch_proc_fops = { -+ .read = (ssize_t (*) (struct file *, char __user *, -+ size_t, loff_t *))switch_proc_read, -+ .write = (ssize_t (*) (struct file *, const char __user *, -+ size_t, loff_t *))switch_proc_write, -+}; -+ -+/* -+ * switch_add_handler -+ */ -+static int switch_add_handler(struct switch_device *switch_dev, -+ struct proc_dir_entry *parent, -+ const struct switch_handler *handler, -+ int inst) -+{ -+ struct switch_handler_entry *she; -+ struct proc_dir_entry *pde; -+ int mode; -+ -+ she = (struct switch_handler_entry *) -+ kzalloc(sizeof(struct switch_handler_entry), GFP_KERNEL); -+ if (!she) { -+ return -ENOMEM; -+ } -+ -+ INIT_LIST_HEAD(&she->node); -+ she->parent = parent; -+ she->dev = switch_dev; -+ she->inst = inst; -+ she->handler = handler; -+ list_add(&she->node, &switch_dev->handlers); -+ -+ mode = 0; -+ if (handler->read != NULL) { -+ mode |= S_IRUSR; -+ } -+ if (handler->write != NULL) { -+ mode |= S_IWUSR; -+ } -+ -+ pde = create_proc_entry(handler->name, mode, parent); -+ if (!pde) { -+ kfree(she); -+ printk("Failed to create node '%s' in parent %p\n", -+ handler->name, parent); -+ return -ENOMEM; -+ } -+ pde->data = (void *)she; -+ pde->proc_fops = &switch_proc_fops; -+ -+ return 0; -+} -+ -+/* -+ * switch_add_handlers -+ */ -+static int switch_add_handlers(struct switch_device *switch_dev, -+ struct proc_dir_entry *parent, -+ const struct switch_handler *handlers, -+ int inst) -+{ -+ while (handlers->name) { -+ int ret = switch_add_handler(switch_dev, -+ parent, handlers, inst); -+ if (ret) { -+ return ret; -+ } -+ handlers++; -+ } -+ -+ return 0; -+} -+ -+/* -+ * switch_remove_vlan_dirs -+ * Removes all vlan directories -+ * -+ * Assumes all vlan directories are empty, should be called after -+ * switch_remove_handlers -+ */ -+static void switch_remove_vlan_dirs(struct switch_device *switch_dev) -+{ -+ struct list_head *pos; -+ struct list_head *tmp; -+ struct switch_vlan_entry *sve; -+ -+ list_for_each_safe(pos, tmp, &switch_dev->vlan_dirs) { -+ sve = list_entry(pos, struct switch_vlan_entry, node); -+ list_del(pos); -+ remove_proc_entry(sve->pde->name, switch_dev->vlan_dir); -+ kfree(sve); -+ } -+} -+ -+/* -+ * switch_remove_handlers -+ * Removes all handlers registered to the given switch_device -+ */ -+static void switch_remove_handlers(struct switch_device *switch_dev) -+{ -+ struct list_head *pos; -+ struct list_head *tmp; -+ struct switch_handler_entry *she; -+ -+ list_for_each_safe(pos, tmp, &switch_dev->handlers) { -+ she = list_entry(pos, struct switch_handler_entry, node); -+ list_del(pos); -+ remove_proc_entry(she->handler->name, she->parent); -+ kfree(she); -+ } -+} -+ -+/* -+ * switch_unregister_proc_nodes -+ * Unregisters all proc nodes related to switch_dev -+ */ -+void switch_unregister_proc_nodes(struct switch_device *switch_dev) -+{ -+ switch_remove_handlers(switch_dev); -+ -+ if (switch_dev->port_dirs) { -+ int i; -+ -+ for (i = 0; i < switch_dev->ports; i++) { -+ if (switch_dev->port_dirs[i]) { -+ remove_proc_entry( -+ switch_dev->port_dirs[i]->name, -+ switch_dev->port_dir); -+ } -+ } -+ } -+ -+ if (switch_dev->port_dir) { -+ remove_proc_entry("port", switch_dev->driver_dir); -+ switch_dev->port_dir = NULL; -+ } -+ -+ if (switch_dev->reg_dir) { -+ remove_proc_entry("reg", switch_dev->reg_dir); -+ switch_dev->reg_dir = NULL; -+ } -+ -+ if (switch_dev->vlan_dir) { -+ switch_remove_vlan_dirs(switch_dev); -+ remove_proc_entry("vlan", switch_dev->driver_dir); -+ switch_dev->vlan_dir = NULL; -+ } -+ -+ if (switch_dev->driver_dir) { -+ remove_proc_entry(switch_dev->name, switch_root); -+ switch_dev->driver_dir = NULL; -+ } -+} -+ -+/* -+ * switch_remove_vlan_dir -+ * Removes vlan dir in switch//vlan/ -+ */ -+int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id) -+{ -+ struct list_head *pos; -+ struct switch_vlan_entry *sve = NULL; -+ -+ list_for_each(pos, &switch_dev->vlan_dirs) { -+ struct switch_vlan_entry *tmp = -+ list_entry(pos, struct switch_vlan_entry, node); -+ if (tmp->vlan_id == vlan_id) { -+ sve = tmp; -+ break; -+ } -+ } -+ -+ if (!sve) { -+ return -ENOENT; -+ } -+ -+ /* -+ * Remove it from the list -+ */ -+ list_del(pos); -+ -+ /* -+ * Remove the handlers -+ */ -+ while (sve->handlers->name) { -+ remove_proc_entry(sve->handlers->name, sve->pde); -+ sve->handlers++; -+ } -+ -+ /* -+ * Remove the proc entry for the dir -+ */ -+ remove_proc_entry(sve->pde->name, switch_dev->vlan_dir); -+ -+ kfree(sve); -+ -+ return 0; -+} -+ -+/* -+ * switch_create_vlan_dir -+ * Creates vlan dir in switch//vlan/ -+ */ -+int switch_create_vlan_dir(struct switch_device *switch_dev, -+ int vlan_id, const struct switch_handler *handlers) -+{ -+ char s[14]; -+ struct proc_dir_entry *pde = NULL; -+ struct switch_vlan_entry *sve = NULL; -+ int ret; -+ struct list_head *pos; -+ -+ /* -+ * Check to see if it exists already -+ */ -+ list_for_each(pos, &switch_dev->vlan_dirs) { -+ sve = list_entry(pos, struct switch_vlan_entry, node); -+ if (sve->vlan_id == vlan_id) { -+ return -EEXIST; -+ } -+ } -+ sve = NULL; -+ -+ /* -+ * Create the vlan directory if we didn't have it before -+ */ -+ if (!switch_dev->vlan_dir) { -+ switch_dev->vlan_dir = proc_mkdir("vlan", -+ switch_dev->driver_dir); -+ if (!switch_dev->vlan_dir) { -+ goto fail; -+ } -+ if (switch_dev->vlan_handlers) { -+ ret = switch_add_handlers(switch_dev, -+ switch_dev->vlan_dir, -+ switch_dev->vlan_handlers, 0); -+ if (ret) { -+ goto fail; -+ } -+ } -+ } -+ -+ /* -+ * Create the vlan_id directory -+ */ -+ snprintf(s, 14, "%d", vlan_id); -+ pde = proc_mkdir(s, switch_dev->vlan_dir); -+ if (!pde) { -+ goto fail; -+ } -+ -+ /* -+ * Create the handlers for this vlan -+ */ -+ if (handlers) { -+ ret = switch_add_handlers(switch_dev, pde, handlers, vlan_id); -+ if (ret) { -+ goto fail; -+ } -+ } -+ -+ /* -+ * Keep track of all the switch vlan entries created -+ */ -+ sve = (struct switch_vlan_entry *) -+ kzalloc(sizeof(struct switch_vlan_entry), GFP_KERNEL); -+ if (!sve) { -+ goto fail; -+ } -+ INIT_LIST_HEAD(&sve->node); -+ sve->handlers = handlers; -+ sve->vlan_id = vlan_id; -+ sve->pde = pde; -+ list_add(&sve->node, &switch_dev->vlan_dirs); -+ -+ return 0; -+ -+fail: -+ if (sve) { -+ kfree(sve); -+ } -+ -+ if (pde) { -+ /* -+ * Remove any proc entries we might have created -+ */ -+ while (handlers->name) { -+ remove_proc_entry(handlers->name, pde); -+ handlers++; -+ } -+ -+ remove_proc_entry(s, switch_dev->driver_dir); -+ } -+ -+ return -ENOMEM; -+} -+ -+/* -+ * switch_register_proc_nodes -+ */ -+int switch_register_proc_nodes(struct switch_device *switch_dev) -+{ -+ int i; -+ int n; -+ -+ switch_dev->port_dirs = kzalloc(switch_dev->ports * -+ sizeof(struct proc_dir_entry *), -+ GFP_KERNEL); -+ if (!switch_dev->port_dirs) { -+ return -ENOMEM; -+ } -+ -+ /* -+ * Create a new proc entry for this switch -+ */ -+ switch_dev->driver_dir = proc_mkdir(switch_dev->name, switch_root); -+ if (!switch_dev->driver_dir) { -+ goto fail; -+ } -+ if (switch_dev->driver_handlers) { -+ switch_add_handlers(switch_dev, -+ switch_dev->driver_dir, -+ switch_dev->driver_handlers, -+ 0); -+ } -+ -+ /* -+ * Create the ports -+ */ -+ switch_dev->port_dir = proc_mkdir("port", switch_dev->driver_dir); -+ if (!switch_dev->port_dir) { -+ goto fail; -+ } -+ for (n = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) { -+ if (switch_dev->port_mask[i / 32] & (1 << i % 32)) { -+ char s[14]; -+ -+ snprintf(s, 14, "%d", i); -+ switch_dev->port_dirs[n] = -+ proc_mkdir(s, switch_dev->port_dir); -+ if (!switch_dev->port_dirs[n]) { -+ goto fail; -+ } -+ if (switch_dev->port_handlers) { -+ switch_add_handlers(switch_dev, -+ switch_dev->port_dirs[n], -+ switch_dev->port_handlers, -+ i); -+ } -+ n++; -+ } -+ } -+ -+ /* -+ * Create the register directory for switch register access. -+ */ -+ if (switch_dev->reg_handlers) { -+ switch_dev->reg_dir = proc_mkdir("reg", switch_dev->driver_dir); -+ if (!switch_dev->reg_dir) { -+ goto fail; -+ } -+ -+ switch_add_handlers(switch_dev, -+ switch_dev->reg_dir, -+ switch_dev->reg_handlers, -+ 0); -+ } -+ -+ /* -+ * Create the vlan directory -+ */ -+ if (switch_dev->vlan_handlers) { -+ switch_dev->vlan_dir = proc_mkdir("vlan", -+ switch_dev->driver_dir); -+ if (!switch_dev->vlan_dir) { -+ goto fail; -+ } -+ if (switch_dev->vlan_handlers) { -+ switch_add_handlers(switch_dev, -+ switch_dev->vlan_dir, -+ switch_dev->vlan_handlers, -+ 0); -+ } -+ } -+ -+ return 0; -+ -+fail: -+ switch_unregister_proc_nodes(switch_dev); -+ return -ENOMEM; -+} -+ -+/* -+ * switch_release -+ */ -+void switch_release(struct switch_device *switch_dev) -+{ -+ kfree(switch_dev); -+} -+ -+/* -+ * switch_alloc -+ */ -+struct switch_device *switch_alloc(void) -+{ -+ struct switch_device *switch_dev = -+ kzalloc(sizeof(struct switch_device), -+ GFP_KERNEL); -+ INIT_LIST_HEAD(&switch_dev->node); -+ INIT_LIST_HEAD(&switch_dev->vlan_dirs); -+ INIT_LIST_HEAD(&switch_dev->handlers); -+ return switch_dev; -+} -+ -+/* -+ * switch_register -+ */ -+int switch_register(struct switch_device *switch_dev) -+{ -+ int ret; -+ int i; -+ -+ /* -+ * Make sure that the number of ports and the port mask make sense -+ */ -+ for (ret = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) { -+ if (switch_dev->port_mask[i / 32] & (1 << i % 32)) { -+ ret++; -+ } -+ } -+ if (ret > switch_dev->ports) { -+ return -EINVAL; -+ } -+ -+ /* -+ * Create the /proc entries -+ */ -+ ret = switch_register_proc_nodes(switch_dev); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * Add it to the list of switches -+ */ -+ down_write(&switch_list_lock); -+ list_add_tail(&switch_dev->node, &switch_list); -+ up_write(&switch_list_lock); -+ -+ printk(KERN_INFO "Registered switch device: %s\n", switch_dev->name); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(switch_register); -+ -+/* -+ * switch_unregister -+ * Unregisters a previously registered switch_device object -+ */ -+void switch_unregister(struct switch_device *switch_dev) -+{ -+ /* -+ * remove the proc entries -+ */ -+ switch_unregister_proc_nodes(switch_dev); -+ -+ /* -+ * Remove it from the list of switches -+ */ -+ down_write(&switch_list_lock); -+ list_del(&switch_dev->node); -+ up_write(&switch_list_lock); -+ -+ printk(KERN_INFO "Unregistered switch device: %s\n", switch_dev->name); -+} -+EXPORT_SYMBOL_GPL(switch_unregister); -+ -+/* -+ * switch_init -+ */ -+static int __init switch_init(void) -+{ -+ switch_root = proc_mkdir("switch", NULL); -+ if (!switch_root) { -+ printk(KERN_WARNING "Failed to make root switch node\n"); -+ return -ENODEV; -+ } -+ return 0; -+} -+module_init(switch_init); -+ -+/* -+ * switch_exit -+ */ -+static void __exit switch_exit(void) -+{ -+ remove_proc_entry("switch", NULL); -+} -+module_exit(switch_exit); -+ -+MODULE_AUTHOR("Patrick Tjin"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Ethernet Switch Class Interface"); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/switch-core.h linux-2.6.30.10-ubi/arch/ubicom32/mach-common/switch-core.h ---- linux-2.6.30.10/arch/ubicom32/mach-common/switch-core.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/switch-core.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,92 @@ -+/* -+ * arch/ubicom32/mach-common/switch-core.h -+ * Private data for the switch module -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _SWITCH_CORE_H_ -+#define _SWITCH_CORE_H_ -+ -+struct switch_handler_entry; -+struct switch_vlan_entry; -+ -+#define SWITCH_PORT_MASK_SIZE 2 -+ -+struct switch_device { -+ struct list_head node; -+ -+ const char *name; -+ void *drvdata; -+ -+ u8_t ports; -+ -+ struct proc_dir_entry *driver_dir; -+ const struct switch_handler *driver_handlers; -+ -+ struct proc_dir_entry *port_dir; -+ struct proc_dir_entry **port_dirs; -+ const struct switch_handler *port_handlers; -+ -+ struct proc_dir_entry *reg_dir; -+ const struct switch_handler *reg_handlers; -+ -+ struct proc_dir_entry *vlan_dir; -+ const struct switch_handler *vlan_handlers; -+ struct list_head vlan_dirs; -+ -+ struct list_head handlers; -+ -+ u32_t port_mask[SWITCH_PORT_MASK_SIZE]; -+}; -+ -+typedef int (*switch_handler_fn)(struct switch_device *, char *buf, int nr); -+struct switch_handler { -+ const char *name; -+ -+ switch_handler_fn read; -+ switch_handler_fn write; -+}; -+ -+#define SWITCH_MAX_BUFSZ 4096 -+ -+static inline void switch_set_drvdata(struct switch_device *switch_dev, void *drvdata) -+{ -+ switch_dev->drvdata = drvdata; -+} -+ -+static inline void *switch_get_drvdata(struct switch_device *switch_dev) -+{ -+ return switch_dev->drvdata; -+} -+ -+extern int switch_create_vlan_dir(struct switch_device *switch_dev, int vlan_id, const struct switch_handler *handlers); -+extern int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id); -+extern void switch_parse_vlan_ports(struct switch_device *switch_dev, char *buf, u32_t *untag, u32_t *ports, u32_t *def); -+ -+extern void switch_release(struct switch_device *switch_dev); -+extern struct switch_device *switch_alloc(void); -+extern int switch_register(struct switch_device *switch_dev); -+extern void switch_unregister(struct switch_device *switch_dev); -+ -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/ubi32-gpio.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ubi32-gpio.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/ubi32-gpio.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ubi32-gpio.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,411 @@ -+/* -+ * arch/ubicom32/mach-common/ubi32-gpio.c -+ * Ubicom gpio driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if defined(CONFIG_PROC_FS) -+#include -+#endif -+ -+#include -+#include -+#include -+ -+#define UBI_GPIO_CHECK_RANGE 0 /* !0 enables range checking */ -+ -+ -+/* -+ * Each I/O port can be configured to operate in one of several -+ * functional modes. One of these modes is GPIO, which causes the -+ * entire port to function as a GPIO port. Since the various port -+ * registers serve the system with other important functions, such as -+ * ethernet, serial, USB, etc., it isn't advantageous to set any of -+ * the ports to be entirely dedicated for GPIO use. The processor -+ * alternatively allows individual bits of a port to be assigned to be -+ * used as GPIO independently from the overall port function. This -+ * bit-by-bit assignment is selected by setting the corresponding bit -+ * in the port's gpio_mask register. When set, the selected bit is -+ * then enabled as a GPIO. If the corresponding bit is set in the -+ * gpio_ctl register of the port, the bit is configured as a GPIO -+ * output. Otherwise, it is an input. -+ * -+ * NOTE: This driver uses the bit-by-bit GPIO function assignment -+ * exclusively and *never* sets the port function registers to the -+ * GPIO function. -+ * -+ * GPIO is not the main function of any of the I/O ports. The port -+ * bit widths are variable from one port to the next, determined by -+ * the more common I/O functions of the ports. For simplicity, this -+ * driver assumes all the ports are 32 bits wide regardless of the -+ * real bit width of the port. GPIO bits are numbered from zero to -+ * MAX_UBICOM_GPIOS. Within a port, the least significant bit is -+ * numbered bit zero, the most significant is bit 31. Since the ports -+ * are considered logically contiguous, GPIO #32 is the zeroth bit in -+ * port #1, and so on. Due to the hardware definition, there are -+ * large gaps in the GPIO numbers representing real pins. -+ * -+ * NOTE: It is up to the programmer to refer to the processor data -+ * sheet to determine which bits in which ports can be accessed and -+ * used for GPIO. -+ * -+ */ -+ -+ -+/* There are 9 ports, A through I. Not all 32 bits in each -+ * port can be a GPIO, but we pretend they are. Its up to the -+ * programmer to refer to the processor data sheet. -+ */ -+#define MAX_UBICOM_GPIOS (9 * 32) /* ARCH_NR_GPIOS */ -+#define NUM_GPIO_PORTS (gpio_bank(MAX_UBICOM_GPIOS)) -+ -+ -+/* GPIO reservation bit map array */ -+static int reserved_gpio_map[NUM_GPIO_PORTS]; -+ -+ -+/* Array of hardware io_port addresses */ -+static struct ubicom32_io_port *gpio_bank_addr[NUM_GPIO_PORTS] = -+{ -+ UBICOM32_IO_PORT(RA), -+ UBICOM32_IO_PORT(RB), -+ UBICOM32_IO_PORT(RC), -+ UBICOM32_IO_PORT(RD), -+ UBICOM32_IO_PORT(RE), -+ UBICOM32_IO_PORT(RF), -+ UBICOM32_IO_PORT(RG), -+ UBICOM32_IO_PORT(RH), -+ UBICOM32_IO_PORT(RI) -+}; -+ -+ -+struct ubi_gpio_chip { -+ /* -+ * Right now, nothing else lives here. -+ */ -+ struct gpio_chip gpio_chip; -+}; -+ -+ -+#if UBI_GPIO_CHECK_RANGE -+inline int check_gpio(unsigned gpio) -+{ -+ if (gpio >= MAX_UBICOM_GPIOS) -+ return -EINVAL; -+ return 0; -+} -+#else -+#define check_gpio(n) (0) -+#endif -+ -+/* -+ * ubi_gpio_get_port -+ * Get the IO port associated with a certain gpio -+ */ -+struct ubicom32_io_port *ubi_gpio_get_port(unsigned gpio) -+{ -+ if (gpio_bank(gpio) > NUM_GPIO_PORTS) { -+ return NULL; -+ } -+ return gpio_bank_addr[gpio_bank(gpio)]; -+} -+ -+/* -+ * ubi_gpio_error() -+ */ -+static void ubi_gpio_error(unsigned gpio) -+{ -+ printk(KERN_ERR "ubicom-gpio: GPIO %d wasn't requested!\n", gpio); -+} -+ -+/* -+ * ubi_port_setup() -+ */ -+static void ubi_port_setup(unsigned gpio, unsigned short usage) -+{ -+ if (!check_gpio(gpio)) { -+ if (usage) { -+ UBICOM32_GPIO_ENABLE(gpio); -+ } else { -+ UBICOM32_GPIO_DISABLE(gpio); -+ } -+ } -+} -+ -+/* -+ * ubi_gpio_request() -+ */ -+static int ubi_gpio_request(struct gpio_chip *chip, unsigned gpio) -+{ -+ unsigned long flags; -+ -+ if (check_gpio(gpio) < 0) -+ return -EINVAL; -+ -+ local_irq_save(flags); -+ -+ if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { -+ printk(KERN_ERR "ubi-gpio: GPIO %d is already reserved!\n", -+ gpio); -+ local_irq_restore(flags); -+ return -EBUSY; -+ } -+ -+ reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); -+ -+ ubi_port_setup(gpio, 1); -+ -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+/* -+ * ubi_gpio_free() -+ */ -+static void ubi_gpio_free(struct gpio_chip *chip, unsigned gpio) -+{ -+ unsigned long flags; -+ -+ if (check_gpio(gpio) < 0) -+ return; -+ -+ local_irq_save(flags); -+ -+ if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { -+ ubi_gpio_error(gpio); -+ local_irq_restore(flags); -+ return; -+ } -+ -+ /* Assert the pin is no longer claimed */ -+ reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); -+ -+ /* Revert port bit to use specified by port->function */ -+ ubi_port_setup(gpio, 0); -+ -+ local_irq_restore(flags); -+} -+ -+/* -+ * ubi_gpio_direction_input() -+ */ -+static int ubi_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) -+{ -+ unsigned long flags; -+ -+ if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { -+ ubi_gpio_error(gpio); -+ return -EINVAL; -+ } -+ -+ local_irq_save(flags); -+ -+ /* Configure pin as gpio */ -+ ubi_port_setup(gpio, 1); -+ -+ /* Assert pin is an input */ -+ UBICOM32_GPIO_SET_PIN_INPUT(gpio); -+ -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+ -+/* -+ * ubi_gpio_direction_output() -+ */ -+static int ubi_gpio_direction_output(struct gpio_chip *chip, -+ unsigned gpio, int value) -+{ -+ unsigned long flags; -+ -+ if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { -+ ubi_gpio_error(gpio); -+ return -EINVAL; -+ } -+ -+ local_irq_save(flags); -+ -+ /* Configure pin as gpio and set initial value in gpio_out register -+ * so that when we enable it as an output, it will have the correct -+ * initial value. -+ */ -+ ubi_port_setup(gpio, 1); -+ if (value) { -+ UBICOM32_GPIO_SET_PIN_HIGH(gpio); -+ } else { -+ UBICOM32_GPIO_SET_PIN_LOW(gpio); -+ } -+ -+ /* Enable the pin as an output */ -+ UBICOM32_GPIO_SET_PIN_OUTPUT(gpio); -+ -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+ -+/* -+ * ubi_gpio_get_value() -+ */ -+static int ubi_gpio_get_value(struct gpio_chip *chip, unsigned gpio) -+{ -+ return 0 != (gpio_bank_addr[gpio_bank(gpio)]->gpio_in & gpio_bit(gpio)); -+} -+ -+ -+/* -+ * ubi_gpio_set_value() -+ */ -+static void ubi_gpio_set_value(struct gpio_chip *chip, unsigned gpio, -+ int arg) -+{ -+ unsigned long flags; -+ local_irq_save(flags); -+ -+ if (arg) { -+ UBICOM32_GPIO_SET_PIN_HIGH(gpio); -+ } else { -+ UBICOM32_GPIO_SET_PIN_LOW(gpio); -+ } -+ -+ local_irq_restore(flags); -+} -+ -+ -+/* -+ * ubi_gpio_to_irq() -+ */ -+static int ubi_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) -+{ -+ return gpio_to_irq(gpio); -+} -+ -+ -+/* -+ * ubi_gpio_init() -+ */ -+int __init ubi_gpio_init(void) -+{ -+ int k; -+ int status; -+ struct ubi_gpio_chip *chip; -+ struct gpio_chip *gc; -+ -+ printk(KERN_INFO "Ubicom GPIO Controller\n"); -+ -+ chip = kzalloc(sizeof(struct ubi_gpio_chip), GFP_KERNEL); -+ if (chip == NULL) -+ return -ENOMEM; -+ -+ gc = &chip->gpio_chip; -+ gc->request = ubi_gpio_request; -+ gc->free = ubi_gpio_free; -+ gc->to_irq = ubi_gpio_to_irq; -+ gc->direction_input = ubi_gpio_direction_input; -+ gc->direction_output = ubi_gpio_direction_output; -+ gc->get = ubi_gpio_get_value; -+ gc->set = ubi_gpio_set_value; -+ gc->can_sleep = 0; -+ gc->base = 0; -+ gc->ngpio = MAX_UBICOM_GPIOS; /* ARCH_NR_GPIOS - 1 */ -+ gc->label = "ubi_gpio"; -+ -+ status = gpiochip_add(gc); -+ if (status != 0) { -+ kfree(chip); -+ return status; -+ } -+ -+ /* Assert all pins are free */ -+ for (k = 0; k < NUM_GPIO_PORTS; k++) { -+ reserved_gpio_map[k] = 0; -+ } -+ -+ return 0; -+} -+ -+#if defined(CONFIG_PROC_FS) -+/* -+ * ubi_get_gpio_dir() -+ */ -+static int ubi_get_gpio_dir(unsigned gpio) -+{ -+ if (gpio_bank_addr[gpio_bank(gpio)]->gpio_ctl & gpio_bit(gpio)) -+ return 1; -+ else -+ return 0; -+} -+ -+/* -+ * gpio_proc_read() -+ */ -+static int ubi_gpio_proc_read(char *buf, char **start, off_t offset, -+ int len, int *unused_i, void *unused_v) -+{ -+ int c, outlen = 0; -+ -+ for (c = 0; c < MAX_UBICOM_GPIOS; c++) { -+ if (!check_gpio(c) && -+ (reserved_gpio_map[gpio_bank(c)] & gpio_bit(c))) { -+ len = sprintf(buf, "GPIO_%d:\t\tGPIO %s\n", c, -+ ubi_get_gpio_dir(c) ? "OUTPUT" : "INPUT"); -+ } else { -+ continue; -+ } -+ -+ buf += len; -+ outlen += len; -+ } -+ return outlen; -+} -+ -+/* -+ * ubi_gpio_register_proc() -+ */ -+static __init int ubi_gpio_register_proc(void) -+{ -+ struct proc_dir_entry *proc_gpio; -+ -+ proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL); -+ if (proc_gpio) -+ proc_gpio->read_proc = ubi_gpio_proc_read; -+ -+ return proc_gpio != NULL; -+} -+device_initcall(ubi_gpio_register_proc); -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/ubicom32hid.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ubicom32hid.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/ubicom32hid.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ubicom32hid.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,557 @@ -+/* -+ * arch/ubicom32/mach-common/ubicom32hid.c -+ * I2C driver for HID coprocessor found on some DPF implementations. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define DRIVER_NAME "ubicom32hid" -+ -+#ifdef DEBUG -+static int ubicom32hid_debug; -+#endif -+ -+static const struct i2c_device_id ubicom32hid_id[] = { -+ { DRIVER_NAME, }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, ubicom32hid_id); -+ -+/* -+ * Define this to make IR checking strict, in general, it's not needed -+ */ -+#undef UBICOM32HID_STRICT_IR_CHECK -+ -+#define UBICOM32HID_CMD_SET_PWM 0x01 -+#define UBICOM32HID_CMD_SET_BL_EN 0x02 -+#define UBICOM32HID_BL_EN_LOW 0x00 -+#define UBICOM32HID_BL_EN_HIZ 0x01 -+#define UBICOM32HID_BL_EN_HI 0x02 -+#define UBICOM32HID_CMD_FLUSH 0x99 -+#define UBICOM32HID_CMD_RESET 0x99 -+#define UBICOM32HID_CMD_GET_IR_SWITCH 0xC0 -+#define UBICOM32HID_CMD_GET_REVISION 0xfd -+#define UBICOM32HID_CMD_GET_DEVICE_ID 0xfe -+#define UBICOM32HID_CMD_GET_VERSION 0xff -+#define UBICOM32HID_DEVICE_ID 0x49 -+ -+#define UBICOM32HID_MAX_BRIGHTNESS_PWM 255 -+ -+/* -+ * Data structure returned by the HID device -+ */ -+struct ubicom32hid_input_data { -+ uint32_t ircmd; -+ uint8_t sw_state; -+ uint8_t sw_changed; -+}; -+ -+/* -+ * Our private data -+ */ -+struct ubicom32hid_data { -+ /* -+ * Pointer to the platform data structure, we need the settings. -+ */ -+ const struct ubicom32hid_platform_data *pdata; -+ -+ /* -+ * Backlight device -+ */ -+ struct backlight_device *bldev; -+ -+ /* -+ * I2C client, for sending messages to the HID device -+ */ -+ struct i2c_client *client; -+ -+ /* -+ * Current intensity, used for get_intensity. -+ */ -+ int cur_intensity; -+ -+ /* -+ * Input subsystem -+ * We won't register an input subsystem if there are no mappings. -+ */ -+ struct input_polled_dev *poll_dev; -+}; -+ -+ -+/* -+ * ubicom32hid_set_intensity -+ */ -+static int ubicom32hid_set_intensity(struct backlight_device *bd) -+{ -+ struct ubicom32hid_data *ud = -+ (struct ubicom32hid_data *)bl_get_data(bd); -+ int intensity = bd->props.brightness; -+ int reg; -+ u8_t val; -+ int ret; -+ -+ /* -+ * If we're blanked the the intensity doesn't matter. -+ */ -+ if ((bd->props.power != FB_BLANK_UNBLANK) || -+ (bd->props.fb_blank != FB_BLANK_UNBLANK)) { -+ intensity = 0; -+ } -+ -+ /* -+ * Set the brightness based on the type of backlight -+ */ -+ if (ud->pdata->type == UBICOM32HID_BL_TYPE_BINARY) { -+ reg = UBICOM32HID_CMD_SET_BL_EN; -+ if (intensity) { -+ val = ud->pdata->invert -+ ? UBICOM32HID_BL_EN_LOW : UBICOM32HID_BL_EN_HI; -+ } else { -+ val = ud->pdata->invert -+ ? UBICOM32HID_BL_EN_HI : UBICOM32HID_BL_EN_LOW; -+ } -+ } else { -+ reg = UBICOM32HID_CMD_SET_PWM; -+ val = ud->pdata->invert -+ ? (UBICOM32HID_MAX_BRIGHTNESS_PWM - intensity) : -+ intensity; -+ } -+ -+ /* -+ * Send the command -+ */ -+ ret = i2c_smbus_write_byte_data(ud->client, reg, val); -+ if (ret < 0) { -+ dev_warn(&ud->client->dev, "Unable to write backlight err=%d\n", -+ ret); -+ return ret; -+ } -+ -+ ud->cur_intensity = intensity; -+ -+ return 0; -+} -+ -+/* -+ * ubicom32hid_get_intensity -+ * Return the current intensity of the backlight. -+ */ -+static int ubicom32hid_get_intensity(struct backlight_device *bd) -+{ -+ struct ubicom32hid_data *ud = -+ (struct ubicom32hid_data *)bl_get_data(bd); -+ -+ return ud->cur_intensity; -+} -+ -+/* -+ * ubicom32hid_verify_data -+ * Verify the data to see if there is any action to be taken -+ * -+ * Returns 0 if no action is to be taken, non-zero otherwise -+ */ -+static int ubicom32hid_verify_data(struct ubicom32hid_data *ud, -+ struct ubicom32hid_input_data *data) -+{ -+ uint8_t *ircmd = (uint8_t *)&(data->ircmd); -+ -+ /* -+ * ircmd == DEADBEEF means ir queue is empty. Since this is a -+ * meaningful code, that means the rest of the message is most likely -+ * correct, so only process the data if the switch state has changed. -+ */ -+ if (data->ircmd == 0xDEADBEEF) { -+ return data->sw_changed != 0; -+ } -+ -+ /* -+ * We have an ircmd which is not empty: -+ * Data[1] should be the complement of Data[0] -+ */ -+ if (ircmd[0] != (u8_t)~ircmd[1]) { -+ return 0; -+ } -+ -+#ifdef UBICOM32HID_STRICT_IR_CHECK -+ /* -+ * It seems that some remote controls don't follow the NEC protocol -+ * properly, so only do this check if the remote does indeed follow the -+ * spec. Data[3] should be the complement of Data[2] -+ */ -+ if (ircmd[2] == (u8_t)~ircmd[3]) { -+ return 1; -+ } -+ -+ /* -+ * For non-compliant remotes, check the system code according to what -+ * they send. -+ */ -+ if ((ircmd[2] != UBICOM32HID_IR_SYSTEM_CODE_CHECK) || -+ (ircmd[3] != UBICOM32HID_IR_SYSTEM_CODE)) { -+ return 0; -+ } -+#endif -+ -+ /* -+ * Data checks out, process -+ */ -+ return 1; -+} -+ -+/* -+ * ubicom32hid_poll_input -+ * Poll the input from the HID device. -+ */ -+static void ubicom32hid_poll_input(struct input_polled_dev *dev) -+{ -+ struct ubicom32hid_data *ud = (struct ubicom32hid_data *)dev->private; -+ const struct ubicom32hid_platform_data *pdata = ud->pdata; -+ struct ubicom32hid_input_data data; -+ struct input_dev *id = dev->input; -+ int i; -+ int sync_needed = 0; -+ uint8_t cmd; -+ int ret; -+ -+ /* -+ * Flush the queue -+ */ -+ cmd = UBICOM32HID_CMD_FLUSH; -+ ret = i2c_master_send(ud->client, &cmd, 1); -+ if (ret < 0) { -+ return; -+ } -+ -+ ret = i2c_smbus_read_i2c_block_data( -+ ud->client, UBICOM32HID_CMD_GET_IR_SWITCH, 6, (void *)&data); -+ if (ret < 0) { -+ return; -+ } -+ -+ /* -+ * Verify the data to see if there is any action to be taken -+ */ -+ if (!ubicom32hid_verify_data(ud, &data)) { -+ return; -+ } -+ -+#ifdef DEBUG -+ if (ubicom32hid_debug) { -+ printk("Polled ircmd=%8x swstate=%2x swchanged=%2x\n", -+ data.ircmd, data.sw_state, data.sw_changed); -+ } -+#endif -+ -+ /* -+ * Process changed switches -+ */ -+ if (data.sw_changed) { -+ const struct ubicom32hid_button *ub = pdata->buttons; -+ for (i = 0; i < pdata->nbuttons; i++, ub++) { -+ uint8_t mask = (1 << ub->bit); -+ if (!(data.sw_changed & mask)) { -+ continue; -+ } -+ -+ sync_needed = 1; -+ input_event(id, ub->type, ub->code, -+ (data.sw_state & mask) ? 1 : 0); -+ } -+ } -+ if (sync_needed) { -+ input_sync(id); -+ } -+ -+ /* -+ * Process ir codes -+ */ -+ if (data.ircmd != 0xDEADBEEF) { -+ const struct ubicom32hid_ir *ui = pdata->ircodes; -+ for (i = 0; i < pdata->nircodes; i++, ui++) { -+ if (ui->ir_code == data.ircmd) { -+ /* -+ * Simulate a up/down event -+ */ -+ input_event(id, ui->type, ui->code, 1); -+ input_sync(id); -+ input_event(id, ui->type, ui->code, 0); -+ input_sync(id); -+ } -+ } -+ } -+} -+ -+ -+/* -+ * Backlight ops -+ */ -+static struct backlight_ops ubicom32hid_blops = { -+ .get_brightness = ubicom32hid_get_intensity, -+ .update_status = ubicom32hid_set_intensity, -+}; -+ -+/* -+ * ubicom32hid_probe -+ */ -+static int ubicom32hid_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct ubicom32hid_platform_data *pdata; -+ struct ubicom32hid_data *ud; -+ int ret; -+ int i; -+ u8 version[2]; -+ char buf[1]; -+ -+ pdata = client->dev.platform_data; -+ if (pdata == NULL) { -+ return -ENODEV; -+ } -+ -+ /* -+ * See if we even have a device available before allocating memory. -+ * -+ * Hard reset the device -+ */ -+ ret = gpio_request(pdata->gpio_reset, "ubicom32hid-reset"); -+ if (ret < 0) { -+ return ret; -+ } -+ gpio_direction_output(pdata->gpio_reset, pdata->gpio_reset_polarity); -+ udelay(100); -+ gpio_set_value(pdata->gpio_reset, !pdata->gpio_reset_polarity); -+ udelay(100); -+ -+ /* -+ * soft reset the device. It sometimes takes a while to do this. -+ */ -+ for (i = 0; i < 50; i++) { -+ buf[0] = UBICOM32HID_CMD_RESET; -+ ret = i2c_master_send(client, buf, 1); -+ if (ret > 0) { -+ break; -+ } -+ udelay(10000); -+ } -+ if (i == 50) { -+ dev_warn(&client->dev, "Unable to reset device\n"); -+ goto fail; -+ } -+ -+ ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_DEVICE_ID); -+ if (ret != UBICOM32HID_DEVICE_ID) { -+ dev_warn(&client->dev, "Incorrect device id %02x\n", buf[0]); -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_VERSION); -+ if (ret < 0) { -+ dev_warn(&client->dev, "Unable to get version\n"); -+ goto fail; -+ } -+ version[0] = ret; -+ -+ ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_REVISION); -+ if (ret < 0) { -+ dev_warn(&client->dev, "Unable to get revision\n"); -+ goto fail; -+ } -+ version[1] = ret; -+ -+ /* -+ * Allocate our private data -+ */ -+ ud = kzalloc(sizeof(struct ubicom32hid_data), GFP_KERNEL); -+ if (!ud) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ ud->pdata = pdata; -+ ud->client = client; -+ -+ /* -+ * Register our backlight device -+ */ -+ ud->bldev = backlight_device_register(DRIVER_NAME, &client->dev, -+ ud, &ubicom32hid_blops); -+ if (IS_ERR(ud->bldev)) { -+ ret = PTR_ERR(ud->bldev); -+ goto fail2; -+ } -+ platform_set_drvdata(client, ud); -+ -+ /* -+ * Start up the backlight with the requested intensity -+ */ -+ ud->bldev->props.power = FB_BLANK_UNBLANK; -+ ud->bldev->props.max_brightness = -+ (pdata->type == UBICOM32HID_BL_TYPE_PWM) ? -+ UBICOM32HID_MAX_BRIGHTNESS_PWM : 1; -+ if (pdata->default_intensity < ud->bldev->props.max_brightness) { -+ ud->bldev->props.brightness = pdata->default_intensity; -+ } else { -+ dev_warn(&client->dev, "Default brightness out of range, " -+ "setting to max\n"); -+ ud->bldev->props.brightness = ud->bldev->props.max_brightness; -+ } -+ -+ ubicom32hid_set_intensity(ud->bldev); -+ -+ /* -+ * Check to see if we have any inputs -+ */ -+ if (!pdata->nbuttons && !pdata->nircodes) { -+ goto done; -+ } -+ -+ /* -+ * We have buttons or codes, we must register an input device -+ */ -+ ud->poll_dev = input_allocate_polled_device(); -+ if (!ud->poll_dev) { -+ ret = -ENOMEM; -+ goto fail3; -+ } -+ -+ /* -+ * Setup the polling to default to 100ms -+ */ -+ ud->poll_dev->poll = ubicom32hid_poll_input; -+ ud->poll_dev->poll_interval = -+ pdata->poll_interval ? pdata->poll_interval : 100; -+ ud->poll_dev->private = ud; -+ -+ ud->poll_dev->input->name = -+ pdata->input_name ? pdata->input_name : "Ubicom32HID"; -+ ud->poll_dev->input->phys = "ubicom32hid/input0"; -+ ud->poll_dev->input->dev.parent = &client->dev; -+ ud->poll_dev->input->id.bustype = BUS_I2C; -+ -+ /* -+ * Set the capabilities by running through the buttons and ir codes -+ */ -+ for (i = 0; i < pdata->nbuttons; i++) { -+ const struct ubicom32hid_button *ub = &pdata->buttons[i]; -+ -+ input_set_capability(ud->poll_dev->input, -+ ub->type ? ub->type : EV_KEY, ub->code); -+ } -+ -+ for (i = 0; i < pdata->nircodes; i++) { -+ const struct ubicom32hid_ir *ui = &pdata->ircodes[i]; -+ -+ input_set_capability(ud->poll_dev->input, -+ ui->type ? ui->type : EV_KEY, ui->code); -+ } -+ -+ ret = input_register_polled_device(ud->poll_dev); -+ if (ret) { -+ goto fail3; -+ } -+ -+done: -+ printk(KERN_INFO DRIVER_NAME ": enabled, version=%02x.%02x\n", -+ version[0], version[1]); -+ -+ return 0; -+ -+fail3: -+ gpio_free(ud->pdata->gpio_reset); -+ backlight_device_unregister(ud->bldev); -+fail2: -+ kfree(ud); -+fail: -+ gpio_free(pdata->gpio_reset); -+ return ret; -+} -+ -+/* -+ * ubicom32hid_remove -+ */ -+static int ubicom32hid_remove(struct i2c_client *client) -+{ -+ struct ubicom32hid_data *ud = -+ (struct ubicom32hid_data *)platform_get_drvdata(client); -+ -+ gpio_free(ud->pdata->gpio_reset); -+ -+ backlight_device_unregister(ud->bldev); -+ -+ if (ud->poll_dev) { -+ input_unregister_polled_device(ud->poll_dev); -+ input_free_polled_device(ud->poll_dev); -+ } -+ -+ platform_set_drvdata(client, NULL); -+ -+ kfree(ud); -+ -+ return 0; -+} -+ -+static struct i2c_driver ubicom32hid_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ .probe = ubicom32hid_probe, -+ .remove = __exit_p(ubicom32hid_remove), -+ .id_table = ubicom32hid_id, -+}; -+ -+/* -+ * ubicom32hid_init -+ */ -+static int __init ubicom32hid_init(void) -+{ -+ return i2c_add_driver(&ubicom32hid_driver); -+} -+module_init(ubicom32hid_init); -+ -+/* -+ * ubicom32hid_exit -+ */ -+static void __exit ubicom32hid_exit(void) -+{ -+ i2c_del_driver(&ubicom32hid_driver); -+} -+module_exit(ubicom32hid_exit); -+ -+MODULE_AUTHOR("Pat Tjin <@ubicom.com>") -+MODULE_DESCRIPTION("Ubicom HID driver"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/ubicom32input.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ubicom32input.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/ubicom32input.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ubicom32input.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,265 @@ -+/* -+ * arch/ubicom32/mach-common/ubicom32input.c -+ * Ubicom32 Input driver -+ * -+ * based on gpio-keys -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ * -+ * -+ * TODO: add groups for inputs which can be sampled together (i.e. I2C) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+struct ubicom32input_data { -+ struct ubicom32input_platform_data *pdata; -+ -+ struct input_polled_dev *poll_dev; -+ -+ /* -+ * collection of previous states for buttons -+ */ -+ u8 prev_state[0]; -+}; -+ -+/* -+ * ubicom32input_poll -+ */ -+static void ubicom32input_poll(struct input_polled_dev *dev) -+{ -+ struct ubicom32input_data *ud = -+ (struct ubicom32input_data *)dev->private; -+ struct ubicom32input_platform_data *pdata = ud->pdata; -+ struct input_dev *id = dev->input; -+ int i; -+ int sync_needed = 0; -+ -+ for (i = 0; i < pdata->nbuttons; i++) { -+ const struct ubicom32input_button *ub = &pdata->buttons[i]; -+ int state = 0; -+ -+ int val = gpio_get_value(ub->gpio); -+ -+ /* -+ * Check to see if the state changed from the last time we -+ * looked -+ */ -+ if (val == ud->prev_state[i]) { -+ continue; -+ } -+ -+ /* -+ * The state has changed, determine if we are "up" or "down" -+ */ -+ ud->prev_state[i] = val; -+ -+ if ((!val && ub->active_low) || (val && !ub->active_low)) { -+ state = 1; -+ } -+ -+ input_event(id, ub->type, ub->code, state); -+ sync_needed = 1; -+ } -+ -+ if (sync_needed) { -+ input_sync(id); -+ } -+} -+ -+/* -+ * ubicom32input_probe -+ */ -+static int __devinit ubicom32input_probe(struct platform_device *pdev) -+{ -+ int i; -+ struct ubicom32input_data *ud; -+ struct input_polled_dev *poll_dev; -+ struct input_dev *input_dev; -+ struct ubicom32input_platform_data *pdata; -+ int ret; -+ -+ pdata = pdev->dev.platform_data; -+ if (!pdata) { -+ return -EINVAL; -+ } -+ -+ ud = kzalloc(sizeof(struct ubicom32input_data) + -+ pdata->nbuttons, GFP_KERNEL); -+ if (!ud) { -+ return -ENOMEM; -+ } -+ ud->pdata = pdata; -+ -+ poll_dev = input_allocate_polled_device(); -+ if (!poll_dev) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ -+ platform_set_drvdata(pdev, ud); -+ -+ ud->poll_dev = poll_dev; -+ poll_dev->private = ud; -+ poll_dev->poll = ubicom32input_poll; -+ -+ /* -+ * Set the poll interval requested, default to 50 msec -+ */ -+ if (pdata->poll_interval) { -+ poll_dev->poll_interval = pdata->poll_interval; -+ } else { -+ poll_dev->poll_interval = 50; -+ } -+ -+ /* -+ * Setup the input device -+ */ -+ input_dev = poll_dev->input; -+ input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input"; -+ input_dev->phys = "ubicom32input/input0"; -+ input_dev->dev.parent = &pdev->dev; -+ input_dev->id.bustype = BUS_HOST; -+ -+ /* -+ * Reserve the GPIOs -+ */ -+ for (i = 0; i < pdata->nbuttons; i++) { -+ const struct ubicom32input_button *ub = &pdata->buttons[i]; -+ -+ ret = gpio_request(ub->gpio, -+ ub->desc ? ub->desc : "ubicom32input"); -+ if (ret < 0) { -+ pr_err("ubicom32input: failed to request " -+ "GPIO %d ret=%d\n", ub->gpio, ret); -+ goto fail2; -+ } -+ -+ ret = gpio_direction_input(ub->gpio); -+ if (ret < 0) { -+ pr_err("ubicom32input: failed to set " -+ "GPIO %d to input ret=%d\n", ub->gpio, ret); -+ goto fail2; -+ } -+ -+ /* -+ * Set the previous state to the non-active stae -+ */ -+ ud->prev_state[i] = ub->active_low; -+ -+ input_set_capability(input_dev, -+ ub->type ? ub->type : EV_KEY, ub->code); -+ } -+ -+ /* -+ * Register -+ */ -+ ret = input_register_polled_device(ud->poll_dev); -+ if (ret) { -+ goto fail2; -+ } -+ -+ return 0; -+ -+fail2: -+ /* -+ * release the GPIOs we have already requested. -+ */ -+ while (--i >= 0) { -+ gpio_free(pdata->buttons[i].gpio); -+ } -+ -+fail: -+ printk(KERN_ERR "Ubicom32Input: Failed to register driver %d", ret); -+ platform_set_drvdata(pdev, NULL); -+ input_free_polled_device(poll_dev); -+ kfree(ud); -+ return ret; -+} -+ -+/* -+ * ubicom32input_remove -+ */ -+static int __devexit ubicom32input_remove(struct platform_device *dev) -+{ -+ struct ubicom32input_data *ud = -+ (struct ubicom32input_data *)platform_get_drvdata(dev); -+ int i; -+ -+ /* -+ * Free the GPIOs -+ */ -+ for (i = 0; i < ud->pdata->nbuttons; i++) { -+ gpio_free(ud->pdata->buttons[i].gpio); -+ } -+ -+ platform_set_drvdata(dev, NULL); -+ input_unregister_polled_device(ud->poll_dev); -+ input_free_polled_device(ud->poll_dev); -+ -+ kfree(ud); -+ -+ return 0; -+} -+ -+static struct platform_driver ubicom32input_driver = { -+ .driver = { -+ .name = "ubicom32input", -+ .owner = THIS_MODULE, -+ }, -+ .probe = ubicom32input_probe, -+ .remove = __devexit_p(ubicom32input_remove), -+}; -+ -+/* -+ * ubicom32input_init -+ */ -+static int __devinit ubicom32input_init(void) -+{ -+ return platform_driver_register(&ubicom32input_driver); -+} -+ -+/* -+ * ubicom32input_exit -+ */ -+static void __exit ubicom32input_exit(void) -+{ -+ platform_driver_unregister(&ubicom32input_driver); -+} -+ -+module_init(ubicom32input_init); -+module_exit(ubicom32input_exit); -+ -+MODULE_AUTHOR("Pat Tjin "); -+MODULE_DESCRIPTION("Ubicom32 Input Driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:ubicom32-input"); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/ubicom32input_i2c.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ubicom32input_i2c.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/ubicom32input_i2c.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/ubicom32input_i2c.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,325 @@ -+/* -+ * arch/ubicom32/mach-common/ubicom32input_i2c.c -+ * Ubicom32 Input driver for I2C -+ * Supports PCA953x and family -+ * -+ * We hog the I2C device, turning it all to input. -+ * -+ * Based on gpio-keys, pca953x -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define UBICOM32INPUT_I2C_REG_INPUT 0 -+#define UBICOM32INPUT_I2C_REG_OUTPUT 1 -+#define UBICOM32INPUT_I2C_REG_INVERT 2 -+#define UBICOM32INPUT_I2C_REG_DIRECTION 3 -+ -+static const struct i2c_device_id ubicom32input_i2c_id[] = { -+ { "ubicom32in_pca9534", 8, }, -+ { "ubicom32in_pca9535", 16, }, -+ { "ubicom32in_pca9536", 4, }, -+ { "ubicom32in_pca9537", 4, }, -+ { "ubicom32in_pca9538", 8, }, -+ { "ubicom32in_pca9539", 16, }, -+ { "ubicom32in_pca9554", 8, }, -+ { "ubicom32in_pca9555", 16, }, -+ { "ubicom32in_pca9557", 8, }, -+ { "ubicom32in_max7310", 8, }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, ubicom32input_i2c_id); -+ -+struct ubicom32input_i2c_data { -+ struct ubicom32input_i2c_platform_data *pdata; -+ -+ struct i2c_client *client; -+ -+ struct input_polled_dev *poll_dev; -+ -+ /* -+ * collection of previous states for buttons -+ */ -+ uint16_t prev_state; -+ -+ uint8_t ngpios; -+}; -+ -+/* -+ * ubicom32input_i2c_write_reg -+ * writes a register to the I2C device. -+ */ -+static int ubicom32input_i2c_write_reg(struct ubicom32input_i2c_data *ud, -+ int reg, uint16_t val) -+{ -+ int ret; -+ -+ if (ud->ngpios <= 8) { -+ ret = i2c_smbus_write_byte_data(ud->client, reg, val); -+ } else { -+ ret = i2c_smbus_write_word_data(ud->client, reg << 1, val); -+ } -+ -+ if (ret < 0) { -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* -+ * ubicom32input_i2c_read_reg -+ * reads a register from the I2C device. -+ */ -+static int ubicom32input_i2c_read_reg(struct ubicom32input_i2c_data *ud, -+ int reg, uint16_t *val) -+{ -+ int ret; -+ -+ if (ud->ngpios <= 8) { -+ ret = i2c_smbus_read_byte_data(ud->client, reg); -+ } else { -+ ret = i2c_smbus_read_word_data(ud->client, reg); -+ } -+ -+ if (ret < 0) { -+ return ret; -+ } -+ -+ *val = (uint16_t)ret; -+ -+ return 0; -+} -+ -+/* -+ * ubicom32input_i2c_poll -+ */ -+static void ubicom32input_i2c_poll(struct input_polled_dev *dev) -+{ -+ struct ubicom32input_i2c_data *ud = -+ (struct ubicom32input_i2c_data *)dev->private; -+ struct ubicom32input_i2c_platform_data *pdata = ud->pdata; -+ struct input_dev *id = dev->input; -+ int i; -+ int sync_needed = 0; -+ uint16_t val; -+ uint16_t change_mask; -+ -+ /* -+ * Try to get the input status, if we fail, bail out, maybe we can do it -+ * next time. -+ */ -+ if (ubicom32input_i2c_read_reg(ud, UBICOM32INPUT_I2C_REG_INPUT, &val)) { -+ return; -+ } -+ -+ /* -+ * see if anything changed by using XOR -+ */ -+ change_mask = ud->prev_state ^ val; -+ ud->prev_state = val; -+ -+ for (i = 0; i < pdata->nbuttons; i++) { -+ const struct ubicom32input_i2c_button *ub = &pdata->buttons[i]; -+ uint16_t mask = 1 << ub->bit; -+ int state = val & mask; -+ -+ /* -+ * Check to see if the state changed from the last time we -+ * looked -+ */ -+ if (!(change_mask & mask)) { -+ continue; -+ } -+ input_event(id, ub->type, ub->code, state); -+ sync_needed = 1; -+ } -+ -+ if (sync_needed) { -+ input_sync(id); -+ } -+} -+ -+/* -+ * ubicom32input_i2c_probe -+ */ -+static int __devinit ubicom32input_i2c_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ int i; -+ struct ubicom32input_i2c_data *ud; -+ struct input_polled_dev *poll_dev; -+ struct input_dev *input_dev; -+ struct ubicom32input_i2c_platform_data *pdata; -+ int ret; -+ uint16_t invert_mask = 0; -+ -+ pdata = client->dev.platform_data; -+ if (!pdata) { -+ return -EINVAL; -+ } -+ -+ ud = kzalloc(sizeof(struct ubicom32input_i2c_data), GFP_KERNEL); -+ if (!ud) { -+ return -ENOMEM; -+ } -+ ud->pdata = pdata; -+ ud->client = client; -+ ud->ngpios = id->driver_data; -+ -+ poll_dev = input_allocate_polled_device(); -+ if (!poll_dev) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ -+ ud->poll_dev = poll_dev; -+ poll_dev->private = ud; -+ poll_dev->poll = ubicom32input_i2c_poll; -+ -+ /* -+ * Set the poll interval requested, default to 100 msec -+ */ -+ if (pdata->poll_interval) { -+ poll_dev->poll_interval = pdata->poll_interval; -+ } else { -+ poll_dev->poll_interval = 100; -+ } -+ -+ /* -+ * Setup the input device -+ */ -+ input_dev = poll_dev->input; -+ input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input I2C"; -+ input_dev->phys = "ubicom32input_i2c/input0"; -+ input_dev->dev.parent = &client->dev; -+ input_dev->id.bustype = BUS_I2C; -+ -+ /* -+ * Set the capabilities -+ */ -+ for (i = 0; i < pdata->nbuttons; i++) { -+ const struct ubicom32input_i2c_button *ub = &pdata->buttons[i]; -+ -+ if (ub->active_low) { -+ invert_mask |= (1 << ub->bit); -+ } -+ -+ input_set_capability(input_dev, -+ ub->type ? ub->type : EV_KEY, ub->code); -+ } -+ -+ /* -+ * Setup the device (all inputs) -+ */ -+ ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_DIRECTION, -+ 0xFFFF); -+ if (ret < 0) { -+ goto fail; -+ } -+ -+ ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_INVERT, -+ invert_mask); -+ if (ret < 0) { -+ goto fail; -+ } -+ -+ /* -+ * Register -+ */ -+ ret = input_register_polled_device(ud->poll_dev); -+ if (ret) { -+ goto fail; -+ } -+ -+ i2c_set_clientdata(client, ud); -+ -+ return 0; -+ -+fail: -+ printk(KERN_ERR "ubicom32input_i2c: Failed to register driver %d\n", -+ ret); -+ input_free_polled_device(poll_dev); -+ kfree(ud); -+ return ret; -+} -+ -+/* -+ * ubicom32input_i2c_remove -+ */ -+static int __devexit ubicom32input_i2c_remove(struct i2c_client *client) -+{ -+ struct ubicom32input_i2c_data *ud = -+ (struct ubicom32input_i2c_data *)i2c_get_clientdata(client); -+ -+ i2c_set_clientdata(client, NULL); -+ input_unregister_polled_device(ud->poll_dev); -+ input_free_polled_device(ud->poll_dev); -+ -+ kfree(ud); -+ -+ return 0; -+} -+ -+static struct i2c_driver ubicom32input_i2c_driver = { -+ .driver = { -+ .name = "ubicom32input_i2c", -+ .owner = THIS_MODULE, -+ }, -+ .remove = __devexit_p(ubicom32input_i2c_remove), -+ .id_table = ubicom32input_i2c_id, -+ .probe = ubicom32input_i2c_probe, -+}; -+ -+/* -+ * ubicom32input_i2c_init -+ */ -+static int __devinit ubicom32input_i2c_init(void) -+{ -+ return i2c_add_driver(&ubicom32input_i2c_driver); -+} -+ -+/* -+ * ubicom32input_i2c_exit -+ */ -+static void __exit ubicom32input_i2c_exit(void) -+{ -+ i2c_del_driver(&ubicom32input_i2c_driver); -+} -+ -+module_init(ubicom32input_i2c_init); -+module_exit(ubicom32input_i2c_exit); -+ -+MODULE_AUTHOR("Pat Tjin "); -+MODULE_DESCRIPTION("Ubicom32 Input Driver I2C"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:ubicom32-input"); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/usb.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/usb.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/usb.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/usb.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,132 @@ -+/* -+ * arch/ubicom32/mach-common/ip5k_usb.c -+ * Ubicom32 architecture usb support. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2007 MontaVista Software, Inc. -+ * Author: Kevin Hilman -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can -+ * redistribute it and/or modify it under the terms of the GNU General -+ * Public License as published by the Free Software Foundation, either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ * See the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "usb_tio.h" -+ -+struct usbtionode *unode = NULL; -+ -+static struct resource usb_resources[] = { -+ [0] = { -+ .start = RJ + 0x800, -+ .end = RJ + 0x1000, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { /* general IRQ */ -+ .start = 1, /* this is a dummy value, the real irq number is passed from kernel_setup_param */ -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+ -+static struct musb_hdrc_eps_bits musb_eps[] = { -+ { "ep1_tx", 4, }, -+ { "ep1_rx", 4, }, -+ { "ep2_tx", 10, }, -+ { "ep2_rx", 10, }, -+ { "ep3_tx", 9, }, -+ { "ep3_rx", 9, }, -+ { "ep4_tx", 9, }, -+ { "ep4_rx", 9, }, -+ { "ep5_tx", 6, }, -+ { "ep5_rx", 6, }, -+}; -+ -+static struct musb_hdrc_config musb_config = { -+ .multipoint = true, -+ .dyn_fifo = false, -+ .soft_con = true, -+ .dma = false, -+ -+ .num_eps = 6, -+ .dma_channels = 0, -+ .ram_bits = 0, -+ .eps_bits = musb_eps, -+}; -+ -+static struct musb_hdrc_platform_data usb_data = { -+#ifdef CONFIG_USB_MUSB_OTG -+ .mode = MUSB_OTG, -+#else -+#ifdef CONFIG_USB_MUSB_HDRC_HCD -+ .mode = MUSB_HOST, -+#else -+#ifdef CONFIG_USB_GADGET_MUSB_HDRC -+ .mode = MUSB_PERIPHERAL, -+#endif -+#endif -+#endif -+ .clock = NULL, -+ .set_clock = NULL, -+ .config = &musb_config, -+}; -+ -+static struct platform_device musb_device = { -+ .name = "musb_hdrc", -+ .id = 0, -+ .dev = { -+ .platform_data = &usb_data, -+ .dma_mask = NULL, -+ .coherent_dma_mask = 0, -+ }, -+ .resource = usb_resources, -+ .num_resources = ARRAY_SIZE(usb_resources), -+}; -+ -+struct usbtio_node *usb_node = NULL; -+void ubi32_usb_init(void) -+{ -+ /* -+ * See if the usbtio is in the device tree. -+ */ -+ usb_node = (struct usbtio_node *)devtree_find_node("usbtio"); -+ if (!usb_node) { -+ printk(KERN_WARNING "usb init failed\n"); -+ return; -+ } -+ -+ usb_resources[1].start = usb_node->dn.recvirq; -+ if (platform_device_register(&musb_device) < 0) { -+ printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n"); -+ return; -+ } -+} -+ -+void ubi32_usb_int_clr(void) -+{ -+ UBICOM32_IO_PORT(RJ)->int_clr = (1 << 3); -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/usb_tio.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/usb_tio.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/usb_tio.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/usb_tio.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,356 @@ -+/* -+ * arch/ubicom32/mach-common/usb_tio.c -+ * Linux side Ubicom USB TIO driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include "usb_tio.h" -+ -+#ifdef CONFIG_SMP -+static DEFINE_SPINLOCK(tio_lock); -+#define USB_TIO_LOCK(lock, flag) spin_lock_irqsave(lock, flag) -+#define USB_TIO_UNLOCK(lock, flag) spin_unlock_irqrestore(lock, flag) -+#define USB_TIO_LOCK_ISLOCKED(lock) spin_try_lock(lock) -+#else -+#define USB_TIO_LOCK(lock, flag) local_irq_save(flag) -+#define USB_TIO_UNLOCK(lock, flag) local_irq_restore(flag) -+#endif -+ -+spinlock_t usb_tio_lock; -+ -+/* -+ * usb_tio_set_hrt_interrupt() -+ */ -+static inline void usb_tio_set_hrt_interrupt(void) -+{ -+ ubicom32_set_interrupt(usb_node->dn.sendirq); -+} -+ -+static inline void usb_tio_wait_hrt(void) -+{ -+ while (unlikely(usb_node->pdesc)); -+} -+ -+#if defined(USB_TIO_DEBUG) -+static void usb_tio_request_verify_magic(volatile struct usb_tio_request *req) -+{ -+ BUG_ON(req->magic != USB_TIO_REQUEST_MAGIC2); -+} -+ -+static void usb_tio_request_clear_magic(volatile struct usb_tio_request *req) -+{ -+ req->magic = 0; -+} -+#endif -+ -+static void usb_tio_request_set_magic(volatile struct usb_tio_request *req) -+{ -+ req->magic = USB_TIO_REQUEST_MAGIC1; -+} -+ -+/* -+ * usb_tio_commit_request() -+ */ -+static inline void usb_tio_commit_request(volatile struct usb_tio_request *request) -+{ -+ wmb(); -+ usb_node->pdesc = request; -+ -+ /* -+ * next thing to do is alway checking if (usb_node->pdesc == NULL) -+ * to see if the request is done, so add a mb() here -+ */ -+ mb(); -+ usb_tio_set_hrt_interrupt(); -+} -+ -+/* -+ * usb_tio_read_u16() -+ * Synchronously read 16 bits. -+ */ -+u8_t usb_tio_read_u16(u32_t address, u16_t *data) -+{ -+ volatile struct usb_tio_request *tio_req = &usb_node->request; -+ unsigned long flag; -+ -+ /* -+ * Wait for any previous request to complete and then make this request. -+ */ -+ USB_TIO_LOCK(&tio_lock, flag); -+ usb_tio_wait_hrt(); -+ -+ /* -+ * Fill in the request. -+ */ -+ tio_req->address = address; -+ tio_req->cmd = USB_TIO_READ16_SYNC; -+ USB_TIO_REQUEST_SET_MAGIC(tio_req); -+ usb_tio_commit_request(tio_req); -+ -+ /* -+ * Wait for the result to show up. -+ */ -+ usb_tio_wait_hrt(); -+ USB_TIO_REQUEST_VERIFY_MAGIC(tio_req); -+ *data = (u16_t)tio_req->data; -+ USB_TIO_REQUEST_CLEAR_MAGIC(tio_req); -+ USB_TIO_UNLOCK(&tio_lock, flag); -+ return USB_TIO_OK; -+} -+ -+/* -+ * usb_tio_read_u8() -+ * Synchronously read 16 bits. -+ */ -+u8_t usb_tio_read_u8(u32_t address, u8_t *data) -+{ -+ volatile struct usb_tio_request *tio_req = &usb_node->request; -+ unsigned long flag; -+ -+ /* -+ * Wait for any previous request to complete and then make this request. -+ */ -+ USB_TIO_LOCK(&tio_lock, flag); -+ usb_tio_wait_hrt(); -+ -+ /* -+ * Fill in the request. -+ */ -+ tio_req->address = address; -+ tio_req->cmd = USB_TIO_READ8_SYNC; -+ USB_TIO_REQUEST_SET_MAGIC(tio_req); -+ -+ /* -+ * commit the request -+ */ -+ usb_tio_commit_request(tio_req); -+ -+ /* -+ * Wait for the result to show up. -+ */ -+ usb_tio_wait_hrt(); -+ USB_TIO_REQUEST_VERIFY_MAGIC(tio_req); -+ *data = (u8_t)tio_req->data; -+ USB_TIO_REQUEST_CLEAR_MAGIC(tio_req); -+ USB_TIO_UNLOCK(&tio_lock, flag); -+ return USB_TIO_OK; -+} -+ -+/* -+ * usb_tio_write_u16() -+ * Asynchronously write 16 bits. -+ */ -+u8_t usb_tio_write_u16(u32_t address, u16_t data) -+{ -+ volatile struct usb_tio_request *tio_req = &usb_node->request; -+ unsigned long flag; -+ -+ /* -+ * Wait for any previous write or pending read to complete. -+ */ -+ USB_TIO_LOCK(&tio_lock, flag); -+ usb_tio_wait_hrt(); -+ -+ tio_req->address = address; -+ tio_req->data = data; -+ tio_req->cmd = USB_TIO_WRITE16_ASYNC; -+ USB_TIO_REQUEST_SET_MAGIC(tio_req); -+ -+ /* -+ * commit the request -+ */ -+ usb_tio_commit_request(tio_req); -+ USB_TIO_UNLOCK(&tio_lock, flag); -+ return USB_TIO_OK; -+} -+ -+/* -+ * usb_tio_write_u8() -+ * Asynchronously write 8 bits. -+ */ -+u8_t usb_tio_write_u8(u32_t address, u8_t data) -+{ -+ volatile struct usb_tio_request *tio_req = &usb_node->request; -+ unsigned long flag; -+ -+ /* -+ * Wait for any previous write or pending read to complete. -+ */ -+ USB_TIO_LOCK(&tio_lock, flag); -+ usb_tio_wait_hrt(); -+ -+ tio_req->address = address; -+ tio_req->data = data; -+ tio_req->cmd = USB_TIO_WRITE8_ASYNC; -+ USB_TIO_REQUEST_SET_MAGIC(tio_req); -+ -+ /* -+ * commit the request -+ */ -+ usb_tio_commit_request(tio_req); -+ USB_TIO_UNLOCK(&tio_lock, flag); -+ return USB_TIO_OK; -+} -+ -+/* -+ * usb_tio_read_fifo() -+ * Synchronously read FIFO. -+ */ -+u8_t usb_tio_read_fifo(u32_t address, u32_t buffer, u32_t bytes) -+{ -+ volatile struct usb_tio_request *tio_req = &usb_node->request; -+ unsigned long flag; -+ -+ /* -+ * Wait for any previous request to complete and then make this request. -+ */ -+ USB_TIO_LOCK(&tio_lock, flag); -+ usb_tio_wait_hrt(); -+ -+ /* -+ * Fill in the request. -+ */ -+ tio_req->address = address; -+ tio_req->cmd = USB_TIO_READ_FIFO_SYNC; -+ tio_req->buffer = buffer; -+ tio_req->transfer_length = bytes; -+ USB_TIO_REQUEST_SET_MAGIC(tio_req); -+ -+ /* -+ * commit the request -+ */ -+ usb_tio_commit_request(tio_req); -+ -+ /* -+ * Wait for the result to show up. -+ */ -+ usb_tio_wait_hrt(); -+ USB_TIO_REQUEST_VERIFY_MAGIC(tio_req); -+ USB_TIO_REQUEST_CLEAR_MAGIC(tio_req); -+ USB_TIO_UNLOCK(&tio_lock, flag); -+ return USB_TIO_OK; -+} -+ -+/* -+ * usb_tio_write_fifo() -+ * Synchronously write 32 bits. -+ */ -+u8_t usb_tio_write_fifo(u32_t address, u32_t buffer, u32_t bytes) -+{ -+ volatile struct usb_tio_request *tio_req = &usb_node->request; -+ unsigned long flag; -+ -+ USB_TIO_LOCK(&tio_lock, flag); -+ usb_tio_wait_hrt(); -+ -+ tio_req->address = address; -+ tio_req->buffer = buffer; -+ tio_req->cmd = USB_TIO_WRITE_FIFO_SYNC; -+ tio_req->transfer_length = bytes; -+ USB_TIO_REQUEST_SET_MAGIC(tio_req); -+ /* -+ * commit the request -+ */ -+ usb_tio_commit_request(tio_req); -+ -+ /* -+ * Wait for the result to show up. -+ */ -+ usb_tio_wait_hrt(); -+ USB_TIO_REQUEST_VERIFY_MAGIC(tio_req); -+ USB_TIO_REQUEST_CLEAR_MAGIC(tio_req); -+ USB_TIO_UNLOCK(&tio_lock, flag); -+ return USB_TIO_OK; -+} -+ -+/* -+ * usb_tio_write_fifo_async() -+ * Asynchronously write 32 bits. -+ */ -+u8_t usb_tio_write_fifo_async(u32_t address, u32_t buffer, u32_t bytes) -+{ -+ volatile struct usb_tio_request *tio_req = &usb_node->request; -+ unsigned long flag; -+ -+ USB_TIO_LOCK(&tio_lock, flag); -+ usb_tio_wait_hrt(); -+ -+ tio_req->address = address; -+ -+ /* -+ * Is it necessary to make a local copy of the buffer? Any chance the URB is aborted before TIO finished the FIFO write? -+ */ -+ tio_req->buffer = buffer; -+ tio_req->cmd = USB_TIO_WRITE_FIFO_SYNC; -+ tio_req->transfer_length = bytes; -+ USB_TIO_REQUEST_SET_MAGIC(tio_req); -+ /* -+ * commit the request -+ */ -+ usb_tio_commit_request(tio_req); -+ USB_TIO_UNLOCK(&tio_lock, flag); -+ return USB_TIO_OK; -+} -+ -+/* -+ * usb_tio_read_int_status() -+ * read and clear the interrupt status registers -+ */ -+void usb_tio_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx) -+{ -+ -+ /* -+ * clear the interrupt must be syncronized with the TIO thread to prevent the racing condiiton -+ * that TIO thread try to set it at same time -+ */ -+ asm volatile ( -+ "1: bset (%0), (%0), #0 \n\t" \ -+ " jmpne.f 1b \n\t" \ -+ : -+ : "a" (&usb_node->usb_vp_control) -+ : "memory", "cc" -+ ); -+ -+ *int_usb = usb_node->usb_vp_hw_int_usb; -+ *int_tx = cpu_to_le16(usb_node->usb_vp_hw_int_tx); -+ *int_rx = cpu_to_le16(usb_node->usb_vp_hw_int_rx); -+ -+ //printk(KERN_INFO "int read %x, %x, %x\n", *int_usb, *int_tx, *int_rx); -+ -+ /* -+ * The interrupt status register is read-clean, so clear it now -+ */ -+ usb_node->usb_vp_hw_int_usb = 0; -+ usb_node->usb_vp_hw_int_tx = 0; -+ usb_node->usb_vp_hw_int_rx = 0; -+ -+ /* -+ * release the lock bit -+ */ -+ usb_node->usb_vp_control &= 0xfffe; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/usb_tio.h linux-2.6.30.10-ubi/arch/ubicom32/mach-common/usb_tio.h ---- linux-2.6.30.10/arch/ubicom32/mach-common/usb_tio.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/usb_tio.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,111 @@ -+/* -+ * arch/ubicom32/mach-common/usb_tio.h -+ * Definitions for usb_tio.c -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifndef _USB_TIO_H -+#define _USB_TIO_H -+ -+#undef USB_TIO_DEBUG -+ -+#define USB_TIO_REQUEST_MAGIC1 0x2307 -+#define USB_TIO_REQUEST_MAGIC2 0x0789 -+#if defined(USB_TIO_DEBUG) -+#define USB_TIO_REQUEST_VERIFY_MAGIC(req) usb_tio_request_verify_magic(req) -+#define USB_TIO_REQUEST_SET_MAGIC(req) usb_tio_request_set_magic(req) -+#define USB_TIO_REQUEST_CLEAR_MAGIC(req) usb_tio_request_clear_magic(req) -+#else -+#define USB_TIO_REQUEST_VERIFY_MAGIC(req) -+#define USB_TIO_REQUEST_SET_MAGIC(req) usb_tio_request_set_magic(req) -+#define USB_TIO_REQUEST_CLEAR_MAGIC(req) -+#endif -+ -+enum USB_TIO_status { -+ USB_TIO_OK, -+ USB_TIO_ERROR, -+ USB_TIO_ERROR_COMMIT, -+}; -+ -+enum USB_TIO_cmds { -+ USB_TIO_READ16_SYNC, -+ USB_TIO_READ8_SYNC, -+ USB_TIO_READ_FIFO_SYNC, -+ -+ USB_TIO_WRITE16_ASYNC, -+ USB_TIO_WRITE8_ASYNC, -+ USB_TIO_WRITE_FIFO_ASYNC, -+ -+ USB_TIO_WRITE16_SYNC, -+ USB_TIO_WRITE8_SYNC, -+ USB_TIO_WRITE_FIFO_SYNC, -+ -+}; -+ -+enum USB_TIO_state { -+ USB_TIO_NORMAL, -+ USB_TIO_DMA_SETUP, -+}; -+ -+struct usb_tio_request { -+ volatile u32_t address; -+ union { -+ volatile u32_t data; -+ volatile u32_t buffer; -+ }; -+ volatile u16_t cmd; -+ const volatile u16_t status; -+ volatile u32_t transfer_length; -+ volatile u32_t thread_mask; -+ volatile u16_t magic; -+}; -+ -+struct usbtio_node { -+ struct devtree_node dn; -+ volatile struct usb_tio_request * volatile pdesc; -+ struct usb_tio_request request; -+ volatile u32_t usb_vp_config; -+ volatile u32_t usb_vp_control; -+ const volatile u32_t usb_vp_status; -+ volatile u16_t usb_vp_hw_int_tx; -+ volatile u16_t usb_vp_hw_int_rx; -+ volatile u8_t usb_vp_hw_int_usb; -+ volatile u8_t usb_vp_hw_int_mask_usb; -+ volatile u16_t usb_vp_hw_int_mask_tx; -+ volatile u16_t usb_vp_hw_int_mask_rx; -+ -+}; -+ -+extern struct usbtio_node *usb_node; -+extern void ubi32_usb_init(void); -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-common/vdc_tio.c linux-2.6.30.10-ubi/arch/ubicom32/mach-common/vdc_tio.c ---- linux-2.6.30.10/arch/ubicom32/mach-common/vdc_tio.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-common/vdc_tio.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,111 @@ -+/* -+ * arch/ubicom32/mach-common/vdc_tio.c -+ * Generic initialization for VDC -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+ -+#include -+#include -+ -+/* -+ * Resources that this driver uses -+ */ -+static struct resource vdc_tio_resources[] = { -+ /* -+ * Send IRQ -+ */ -+ [0] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Receive IRQ (optional) -+ */ -+ [1] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Memory Mapped Registers -+ */ -+ [2] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+/* -+ * The platform_device structure which is passed to the driver -+ */ -+static struct platform_device vdc_tio_platform_device = { -+ .name = "ubicom32fb", -+ .id = -1, -+ .resource = vdc_tio_resources, -+ .num_resources = ARRAY_SIZE(vdc_tio_resources), -+}; -+ -+/* -+ * vdc_tio_init -+ * Checks the device tree and instantiates the driver if found -+ */ -+void __init vdc_tio_init(void) -+{ -+ /* -+ * Check the device tree for the vdc_tio -+ */ -+ struct vdc_tio_node *vdc_node = -+ (struct vdc_tio_node *)devtree_find_node("vdctio"); -+ if (!vdc_node) { -+ printk(KERN_WARNING "No vdc_tio found\n"); -+ return; -+ } -+ -+ /* -+ * Fill in the resources and platform data from devtree information -+ */ -+ vdc_tio_resources[0].start = vdc_node->dn.sendirq; -+ vdc_tio_resources[1].start = vdc_node->dn.recvirq; -+ vdc_tio_resources[2].start = (u32_t)vdc_node->regs; -+ vdc_tio_resources[2].end = (u32_t)vdc_node->regs + -+ sizeof(struct vdc_tio_vp_regs); -+ -+ /* -+ * Try to get the device registered -+ */ -+ if (platform_device_register(&vdc_tio_platform_device) < 0) { -+ printk(KERN_WARNING "VDC failed to register\n"); -+ } -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip5k/board-ip5160dev.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/board-ip5160dev.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip5k/board-ip5160dev.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/board-ip5160dev.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,109 @@ -+/* -+ * arch/ubicom32/mach-ip5k/board-ip5160dev.c -+ * Platform initialization for ip5160dev board. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+ -+#include -+#include -+#ifdef CONFIG_SERIAL_UBI32_SERDES -+#include -+#endif -+ -+/* -+ * Factory Default Button on the board at PXn -+ * TODO: This is just a placeholder and it needs to include proper header files -+ */ -+struct ubicom32fdb_platform_data { -+ int fdb_gpio; -+ bool fdb_polarity; -+}; -+ -+static struct ubicom32fdb_platform_data ip5160dev_fdb_data = { -+ .fdb_gpio = 0, -+ .fdb_polarity = true, -+}; -+ -+static struct platform_device ip5160dev_fdb_device = { -+ .name = "ubicom32fdb", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip5160dev_fdb_data, -+ }, -+}; -+ -+#ifdef CONFIG_SERIAL_UBI32_SERDES -+static struct resource ip5160dev_ubicom32_suart_resources[] = { -+ { -+ .start = RD, -+ .end = RD, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = PORT_OTHER_INT(RD), -+ .end = PORT_OTHER_INT(RD), -+ .flags = IORESOURCE_IRQ, -+ }, -+ { -+ .start = 240000000, -+ .end = 240000000, -+ .flags = UBICOM32_SUART_IORESOURCE_CLOCK, -+ }, -+}; -+ -+static struct platform_device ip5160dev_ubicom32_suart_device = { -+ .name = "ubicom32suart", -+ .id = -1, -+ .num_resources = ARRAY_SIZE(ip5160dev_ubicom32_suart_resources), -+ .resource = ip5160dev_ubicom32_suart_resources, -+}; -+#endif -+ -+/* -+ * List of all devices in our system -+ */ -+static struct platform_device *ip5160dev_devices[] __initdata = { -+#ifdef CONFIG_SERIAL_UBI32_SERDES -+ &ip5160dev_ubicom32_suart_device, -+#endif -+ &ip5160dev_fdb_device, -+}; -+ -+/* -+ * ip5160dev_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip5160dev_init(void) -+{ -+ ubi_gpio_init(); -+ printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); -+ platform_add_devices(ip5160dev_devices, ARRAY_SIZE(ip5160dev_devices)); -+ return 0; -+} -+ -+arch_initcall(ip5160dev_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip5k/board-ip5160rgw.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/board-ip5160rgw.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip5k/board-ip5160rgw.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/board-ip5160rgw.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,75 @@ -+/* -+ * arch/ubicom32/mach-ip5k/board-ip5160rgw.c -+ * Platform initialization for ip5160rgw board. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * Factory Default Button on the board at PXn -+ * TODO: This is just a placeholder and it needs to include proper header files -+ */ -+struct ubicom32fdb_platform_data { -+ int fdb_gpio; -+ bool fdb_polarity; -+}; -+ -+static struct ubicom32fdb_platform_data ip5160rgw_fdb_data = { -+ .fdb_gpio = 0, -+ .fdb_polarity = true, -+}; -+ -+static struct platform_device ip5160rgw_fdb_device = { -+ .name = "ubicom32fdb", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip5160rgw_fdb_data, -+ }, -+}; -+ -+/* -+ * List of all devices in our system -+ */ -+static struct platform_device *ip5160rgw_devices[] __initdata = { -+ &ip5160rgw_fdb_device, -+}; -+ -+/* -+ * ip5160rgw_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip5160rgw_init(void) -+{ -+ ubi_gpio_init(); -+ printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); -+ platform_add_devices(ip5160rgw_devices, ARRAY_SIZE(ip5160rgw_devices)); -+ return 0; -+} -+ -+arch_initcall(ip5160rgw_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip5k/board-ip5170dpf.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/board-ip5170dpf.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip5k/board-ip5170dpf.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/board-ip5170dpf.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,279 @@ -+/* -+ * arch/ubicom32/mach-ip5k/board-ip5170dpf.c -+ * Platform initialization for ip5160dpf board. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * LEDs -+ * -+ * WLAN PD9 (Note this is shared with MISO, but we don't use it) -+ * WPS PD8 -+ * -+ * TODO: check triggers, are they generic? -+ */ -+static struct gpio_led ip5170dpf_gpio_leds[] = { -+ { -+ .name = "d31:green:WLAN1", -+ .default_trigger = "WLAN1", -+ .gpio = GPIO_RD_9, -+ .active_low = 1, -+ }, -+ { -+ .name = "d30:green:WPS", -+ .default_trigger = "WPS", -+ .gpio = GPIO_RD_8, -+ .active_low = 1, -+ }, -+}; -+ -+static struct gpio_led_platform_data ip5170dpf_gpio_led_platform_data = { -+ .num_leds = 2, -+ .leds = ip5170dpf_gpio_leds, -+}; -+ -+static struct platform_device ip5170dpf_gpio_leds_device = { -+ .name = "leds-gpio", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip5170dpf_gpio_led_platform_data, -+ }, -+}; -+ -+/* -+ * Backlight on the board PD0, hardware PWM -+ */ -+static const struct ubicom32hid_button ip5170dpf_ubicom32hid_buttons[] = { -+ { -+ .type = EV_KEY, -+ .code = KEY_UP, -+ .bit = 0, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_LEFT, -+ .bit = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_RIGHT, -+ .bit = 2, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_DOWN, -+ .bit = 3, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ENTER, -+ .bit = 4, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_MENU, -+ .bit = 5, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ESC, -+ .bit = 7, -+ }, -+}; -+ -+static const struct ubicom32hid_ir ip5170dpf_ubicom32hid_ircodes[] = { -+ { -+ .type = EV_KEY, -+ .code = KEY_UP, -+ .ir_code = 0xF807916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_DOWN, -+ .ir_code = 0xF20D916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_LEFT, -+ .ir_code = 0xF609916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_RIGHT, -+ .ir_code = 0xF40B916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ENTER, -+ .ir_code = 0xF50A916E -+ }, -+ { /* rotate */ -+ .type = EV_KEY, -+ .code = KEY_FN_F1, -+ .ir_code = 0xF906916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_MENU, -+ .ir_code = 0xF708916E -+ }, -+ { /* font size */ -+ .type = EV_KEY, -+ .code = KEY_FN_F2, -+ .ir_code = 0xF30C916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ESC, -+ .ir_code = 0xF10E916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_VOLUMEUP, -+ .ir_code = 0xF00F916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_VOLUMEDOWN, -+ .ir_code = 0xED12916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_MUTE, -+ .ir_code = 0xEA15916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_INFO, -+ .ir_code = 0xEF10916E -+ }, -+ { /* Like */ -+ .type = EV_KEY, -+ .code = KEY_FN_F3, -+ .ir_code = 0xEE11916E -+ }, -+ { /* Dislike */ -+ .type = EV_KEY, -+ .code = KEY_FN_F4, -+ .ir_code = 0xEB14916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_POWER, -+ .ir_code = 0xFD02916E -+ }, -+}; -+ -+static struct ubicom32hid_platform_data ip5170dpf_ubicom32hid_platform_data = { -+ .gpio_reset = GPIO_RA_4, -+ .gpio_reset_polarity = 0, -+ .type = UBICOM32HID_BL_TYPE_BINARY, -+ .invert = 0, -+ .default_intensity = 1, -+ .buttons = ip5170dpf_ubicom32hid_buttons, -+ .nbuttons = ARRAY_SIZE(ip5170dpf_ubicom32hid_buttons), -+ .ircodes = ip5170dpf_ubicom32hid_ircodes, -+ .nircodes = ARRAY_SIZE(ip5170dpf_ubicom32hid_ircodes), -+}; -+ -+/* -+ * Devices on the I2C bus -+ */ -+static struct i2c_board_info __initdata ip5170dpf_i2c_board_info[] = { -+ /* -+ * U24, ubicom32hid -+ */ -+ { -+ .type = "ubicom32hid", -+ .addr = 0x08, -+ .platform_data = &ip5170dpf_ubicom32hid_platform_data, -+ }, -+ -+ /* -+ * U14, CS4350 DAC, address 0x4B -+ */ -+}; -+ -+/* -+ * I2C bus on the board, SDA PF13, SCL PF14 -+ */ -+static struct i2c_gpio_platform_data ip5170dpf_i2c_data = { -+ .sda_pin = GPIO_RF_13, -+ .scl_pin = GPIO_RF_14, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+ .scl_is_output_only = 1, -+ .udelay = 5, -+}; -+ -+static struct platform_device ip5170dpf_i2c_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip5170dpf_i2c_data, -+ }, -+}; -+ -+/* -+ * List of all devices in our system -+ */ -+static struct platform_device *ip5170dpf_devices[] __initdata = { -+ &ip5170dpf_i2c_device, -+ &ip5170dpf_gpio_leds_device, -+}; -+ -+/* -+ * ip5170dpf_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip5170dpf_init(void) -+{ -+ ubi_gpio_init(); -+ -+ vdc_tio_init(); -+ -+ printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); -+ platform_add_devices(ip5170dpf_devices, ARRAY_SIZE(ip5170dpf_devices)); -+ -+ printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); -+ i2c_register_board_info(0, ip5170dpf_i2c_board_info, ARRAY_SIZE(ip5170dpf_i2c_board_info)); -+ -+ return 0; -+} -+ -+arch_initcall(ip5170dpf_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip5k/Kconfig linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/Kconfig ---- linux-2.6.30.10/arch/ubicom32/mach-ip5k/Kconfig 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/Kconfig 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,28 @@ -+ -+config IP5170DPF -+ bool "IP5170DPF" -+ select UBICOM32_V3 -+ select I2C -+ select I2C_GPIO -+ select FB -+ select FB_UBICOM32 -+ select BACKLIGHT_LCD_SUPPORT -+ select BACKLIGHT_CLASS_DEVICE -+ select UBICOM_HID -+ select NEW_LEDS -+ select LEDS_CLASS -+ select LEDS_GPIO -+ help -+ IP5170 Digital Picture Frame board, 8005-1113, IP5K-BEV-0011-13 v1.3 -+ -+config IP5160DEV -+ bool "IP5160Dev_Ver1Dot1" -+ select UBICOM32_V3 -+ help -+ Ubicom StreamEngine 5000 Development Board, IP5K-BDV-0004-11 v1.1 -+ -+config IP5160EVAL -+ bool "IP5160RGWEval_Ver2Rev2" -+ select UBICOM32_V3 -+ help -+ Ubicom StreamEngine 5000 RGW Evaluation Board, IP5K-RGW-0004-11 v2.2 -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip5k/Makefile linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/Makefile ---- linux-2.6.30.10/arch/ubicom32/mach-ip5k/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip5k/Makefile 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,31 @@ -+# -+# arch/ubicom32/mach-ip5k/Makefile -+# Makefile for boards which have an ip5k on them. -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+ -+obj-$(CONFIG_IP5170DPF) += board-ip5170dpf.o -+obj-$(CONFIG_IP5160DEV) += board-ip5160dev.o -+obj-$(CONFIG_IP5160EVAL) += board-ip5160rgw.o -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7145dpf.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7145dpf.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7145dpf.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7145dpf.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,715 @@ -+/* -+ * arch/ubicom32/mach-ip7k/board-ip7145dpf.c -+ * Board file for IP7145DPF, rev 1.0, P/N 8007-0410 -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+/****************************************************************************** -+ * SD/IO Port F (Slot 1) platform data -+ */ -+static struct resource ip7145dpf_portf_sd_resources[] = { -+ /* -+ * Send IRQ -+ */ -+ [0] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Receive IRQ -+ */ -+ [1] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Memory Mapped Registers -+ */ -+ [2] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+static struct ubicom32sd_card ip7145dpf_portf_sd_cards[] = { -+ [0] = { -+ .pin_wp = IP7145DPF_IOB0, -+ .wp_polarity = 1, -+ .pin_pwr = IP7145DPF_IOB4, -+ .pin_cd = GPIO_RA_4, -+ }, -+ [1] = { -+ .pin_wp = IP7145DPF_IOB1, -+ .wp_polarity = 1, -+ .pin_pwr = IP7145DPF_IOB5, -+ .pin_cd = GPIO_RA_6, -+ }, -+}; -+ -+static struct ubicom32sd_platform_data ip7145dpf_portf_sd_platform_data = { -+ .ncards = 2, -+ .cards = ip7145dpf_portf_sd_cards, -+}; -+ -+static struct platform_device ip7145dpf_portf_sd_device = { -+ .name = "ubicom32sd", -+ .id = 0, -+ .resource = ip7145dpf_portf_sd_resources, -+ .num_resources = ARRAY_SIZE(ip7145dpf_portf_sd_resources), -+ .dev = { -+ .platform_data = &ip7145dpf_portf_sd_platform_data, -+ }, -+ -+}; -+ -+/* -+ * ip7145dpf_portf_sd_init -+ */ -+static void ip7145dpf_portf_sd_init(void) -+{ -+ /* -+ * Check the device tree for the sd_tio -+ */ -+ struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd"); -+ if (!sd_node) { -+ printk(KERN_INFO "PortF SDTIO not found\n"); -+ return; -+ } -+ -+ /* -+ * Fill in the resources and platform data from devtree information -+ */ -+ ip7145dpf_portf_sd_resources[0].start = sd_node->dn.sendirq; -+ ip7145dpf_portf_sd_resources[1].start = sd_node->dn.recvirq; -+ ip7145dpf_portf_sd_resources[2].start = (u32_t)&(sd_node->regs); -+ ip7145dpf_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); -+ -+ platform_device_register(&ip7145dpf_portf_sd_device); -+} -+ -+/****************************************************************************** -+ * SD/IO Port B (Slot 2) platform data -+ */ -+static struct resource ip7145dpf_portb_sd_resources[] = { -+ /* -+ * Send IRQ -+ */ -+ [0] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Receive IRQ -+ */ -+ [1] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Memory Mapped Registers -+ */ -+ [2] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+static struct ubicom32sd_card ip7145dpf_portb_sd_cards[] = { -+ [0] = { -+ .pin_wp = IP7145DPF_IOB2, -+ .wp_polarity = 1, -+ .pin_pwr = IP7145DPF_IOB6, -+ .pin_cd = IP7145DPF_IOB3, -+ }, -+}; -+ -+static struct ubicom32sd_platform_data ip7145dpf_portb_sd_platform_data = { -+ .ncards = 1, -+ .cards = ip7145dpf_portb_sd_cards, -+}; -+ -+static struct platform_device ip7145dpf_portb_sd_device = { -+ .name = "ubicom32sd", -+ .id = 1, -+ .resource = ip7145dpf_portb_sd_resources, -+ .num_resources = ARRAY_SIZE(ip7145dpf_portb_sd_resources), -+ .dev = { -+ .platform_data = &ip7145dpf_portb_sd_platform_data, -+ }, -+ -+}; -+ -+/* -+ * ip7145dpf_portb_sd_init -+ */ -+static void ip7145dpf_portb_sd_init(void) -+{ -+ /* -+ * Check the device tree for the sd_tio -+ */ -+ struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd"); -+ if (!sd_node) { -+ printk(KERN_INFO "PortB SDTIO not found\n"); -+ return; -+ } -+ -+ /* -+ * Fill in the resources and platform data from devtree information -+ */ -+ ip7145dpf_portb_sd_resources[0].start = sd_node->dn.sendirq; -+ ip7145dpf_portb_sd_resources[1].start = sd_node->dn.recvirq; -+ ip7145dpf_portb_sd_resources[2].start = (u32_t)&(sd_node->regs); -+ ip7145dpf_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); -+ -+ platform_device_register(&ip7145dpf_portb_sd_device); -+} -+ -+ -+#ifdef IP7145DPF_USE_MMC_SPI -+/****************************************************************************** -+ * SPI over GPIO (MMC_SPI) -+ */ -+#include -+#include -+#include -+#include -+ -+#define MMC_CS GPIO_RF_5 // PF5 D3 -+#define MMC_CD GPIO_RA_4 // PA4 CD -+#define MMC_WP IP7145DPF_IOB0 // IOB0 WP -+#define MMC_PWR IP7145DPF_IOB4 // IOB4 PWR -+ -+/* -+ * SPI bus over GPIO (for SD card) -+ */ -+static struct ubicom32_spi_gpio_platform_data ip7145dpf_spi_gpio_data = { -+ .pin_mosi = GPIO_RF_0, // PF0 CMD -+ .pin_miso = GPIO_RF_2, // PF2 D0 -+ .pin_clk = GPIO_RF_1, // PF1 CLK -+ .bus_num = 0, // We'll call this SPI bus 0 -+ .num_chipselect = 1, // only one device on this SPI bus -+}; -+ -+static struct platform_device ip7145dpf_spi_gpio_device = { -+ .name = "ubicom32-spi-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip7145dpf_spi_gpio_data, -+ }, -+}; -+ -+/* -+ * ip7145dpf_mmc_spi_setpower_slot_a -+ * Set the power state for slot A -+ */ -+static void ip7145dpf_mmc_spi_setpower_slot_a(struct device *dev, unsigned int vdd) -+{ -+ struct mmc_spi_platform_data *pd = dev->platform_data; -+ -+ /* -+ * Power is inverted, we could tell the IOB to do it, but it's cleaner this way. -+ */ -+ if ((1 << vdd) & pd->ocr_mask) { -+ gpio_set_value(MMC_PWR, 0); -+ return; -+ } -+ gpio_set_value(MMC_PWR, 1); -+} -+ -+/* -+ * ip7145dpf_mmc_spi_get_cd_slot_a -+ * Get the CD bit for slot A -+ */ -+static int ip7145dpf_mmc_spi_get_cd_slot_a(struct device *dev) -+{ -+ /* -+ * Note that the sense of the GPIO is inverted -+ */ -+ return !gpio_get_value(MMC_CD); -+} -+ -+/* -+ * ip7145dpf_mmc_spi_get_ro_slot_a -+ * Get the WP bit for slot A -+ */ -+static int ip7145dpf_mmc_spi_get_ro_slot_a(struct device *dev) -+{ -+ /* -+ * Note that the sense of the GPIO is inverted, we could tell the IOB to do it, but -+ * it's clearer this way. -+ */ -+ return !gpio_get_value(MMC_WP); -+} -+ -+/* -+ * ip7145dpf_mmc_spi_exit_slot_a -+ * Free the appropriate GPIOs for slot A SD slot. -+ */ -+static void ip7145dpf_mmc_spi_exit_slot_a(struct device *dev, void *appdata) -+{ -+ gpio_free(MMC_CD); -+ gpio_free(MMC_CS); -+ gpio_free(MMC_WP); -+ gpio_free(MMC_PWR); -+ platform_device_unregister(&ip7145dpf_spi_gpio_device); -+} -+ -+/* -+ * ip7145dpf_mmc_spi_init_slot_a -+ * Allocate the appropriate GPIOs for slot A SD slot. -+ * WP is on IOB0, CD is PA4, CS is on PF5 -+ * TODO: make CD an interrupt -+ */ -+static int ip7145dpf_mmc_spi_init_slot_a(void) -+{ -+ int ret = gpio_request(MMC_CD, "mmc-a-cd"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request mmc-a-cd pin\n", __FUNCTION__); -+ return -ENOSYS; -+ } -+ gpio_direction_input(MMC_CD); -+ -+ ret = gpio_request(MMC_CS, "mmc-a-cs"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request mmc-a-cs pin\n", __FUNCTION__); -+ goto no_cs; -+ } -+ gpio_direction_output(MMC_CS, 0); -+ -+ ret = gpio_request(MMC_WP, "mmc-a-wp"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request mmc-a-wp pin\n", __FUNCTION__); -+ goto no_wp; -+ } -+ gpio_direction_input(MMC_WP); -+ -+ /* -+ * Start off with power off -+ */ -+ ret = gpio_request(MMC_PWR, "mmc-a-pwr"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request mmc-a-pwr pin\n", __FUNCTION__); -+ goto no_pwr; -+ } -+ ret = gpio_direction_output(MMC_PWR, 1); -+ -+ return 0; -+ -+no_pwr: -+ gpio_free(MMC_WP); -+ -+no_wp: -+ gpio_free(MMC_CS); -+ -+no_cs: -+ gpio_free(MMC_CD); -+ return -ENOSYS; -+} -+ -+/* -+ * MMC_SPI driver (currently bitbang) -+ */ -+static struct mmc_spi_platform_data ip7145dpf_mmc_platform_data = { -+ .ocr_mask = MMC_VDD_33_34, -+ .exit = ip7145dpf_mmc_spi_exit_slot_a, -+ .get_ro = ip7145dpf_mmc_spi_get_ro_slot_a, -+ .get_cd = ip7145dpf_mmc_spi_get_cd_slot_a, -+ -+ .setpower = ip7145dpf_mmc_spi_setpower_slot_a, -+ .powerup_msecs = 500, -+ -+ .detect_delay = 100, -+ -+ .caps = MMC_CAP_NEEDS_POLL, -+}; -+ -+static struct ubicom32_spi_gpio_controller_data ip7145dpf_mmc_controller_data = { -+ .pin_cs = MMC_CS, -+}; -+ -+static struct spi_board_info ip7145dpf_spi_board_info[] = { -+ { -+ .modalias = "mmc_spi", -+ .bus_num = 0, -+ .chip_select = 0, -+ .max_speed_hz = 2000000, -+ .platform_data = &ip7145dpf_mmc_platform_data, -+ .controller_data = &ip7145dpf_mmc_controller_data, -+ } -+}; -+#endif /* IP7145DPF_USE_MMC_SPI */ -+ -+/* -+ * ip7145dpf_u72_setup -+ * Called by I2C to tell us that u72 is setup. -+ * -+ * This function is called by I2C to tell us that u72 has been setup. All -+ * devices which rely on this chip being initialized (or even present) need to -+ * be initialized in this function otherwise they may get initialized too early. -+ * -+ * Currently the only device depending on u72 is the SPI -+ */ -+static int __init ip7145dpf_u72_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *context) -+{ -+#ifdef IP7145DPF_USE_MMC_SPI -+ if (ip7145dpf_mmc_spi_init_slot_a()) { -+ printk(KERN_ERR "%s: could not request mmc resources\n", __FUNCTION__); -+ } else { -+ printk(KERN_INFO "%s: registering SPI resources\n", __FUNCTION__); -+ spi_register_board_info(ip7145dpf_spi_board_info, ARRAY_SIZE(ip7145dpf_spi_board_info)); -+ platform_device_register(&ip7145dpf_spi_gpio_device); -+ } -+#else -+ /* -+ * Initialize the Port F/Port B SD slots -+ */ -+ ip7145dpf_portf_sd_init(); -+ ip7145dpf_portb_sd_init(); -+#endif -+ return 0; -+} -+ -+/****************************************************************************** -+ * LCD VGH on the board at PE6 -+ */ -+static struct ubicom32lcdpower_platform_data ip7145dpf_lcdpower_data = { -+ .vgh_gpio = GPIO_RE_6, -+ .vgh_polarity = true, -+}; -+ -+static struct platform_device ip7145dpf_lcdpower_device = { -+ .name = "ubicom32lcdpower", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip7145dpf_lcdpower_data, -+ }, -+}; -+ -+/****************************************************************************** -+ * Backlight on the board PD0, hardware PWM -+ */ -+static struct ubicom32bl_platform_data ip7145dpf_backlight_data = { -+ .type = UBICOM32BL_TYPE_PWM, -+ .pwm_channel = 2, -+ .pwm_prescale = 15, -+ .pwm_period = 60, -+ .default_intensity = 0x80, -+}; -+ -+static struct platform_device ip7145dpf_backlight_device = { -+ .name = "ubicom32bl", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip7145dpf_backlight_data, -+ }, -+}; -+ -+/****************************************************************************** -+ * Ubicom32Input on I2C, U48 MAX7310, address 0x18, 8 bits -+ */ -+static struct ubicom32input_i2c_button ip7145dpf_ubicom32input_i2c_u48_buttons[] = { -+ { -+ .type = EV_KEY, -+ .code = KEY_UP, -+ .bit = 0, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_LEFT, -+ .bit = 1, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_RIGHT, -+ .bit = 2, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_DOWN, -+ .bit = 3, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ENTER, -+ .bit = 4, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_MENU, -+ .bit = 5, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ESC, -+ .bit = 6, -+ .active_low = 1, -+ }, -+}; -+ -+static struct ubicom32input_i2c_platform_data ip7145dpf_ubicom32input_i2c_u48_platform_data = { -+ .buttons = ip7145dpf_ubicom32input_i2c_u48_buttons, -+ .nbuttons = ARRAY_SIZE(ip7145dpf_ubicom32input_i2c_u48_buttons), -+ .name = "Ubicom32 Input I2C U48", -+}; -+ -+/****************************************************************************** -+ * Additional GPIO chips -+ */ -+static struct pca953x_platform_data ip7145dpf_gpio_u72_platform_data = { -+ .gpio_base = IP7145DPF_U72_BASE, -+ .setup = ip7145dpf_u72_setup, -+}; -+ -+/****************************************************************************** -+ * Devices on the I2C bus -+ */ -+static struct i2c_board_info __initdata ip7145dpf_i2c_board_info[] = { -+ /* -+ * U51, S35390A RTC, address 0x30 -+ */ -+ { -+ .type = "s35390a", -+ .addr = 0x30, -+ }, -+ -+ /* -+ * U48, MAX7310 IO expander, 8 bits, address 0x18 -+ */ -+ { -+ .type = "ubicom32in_max7310", -+ .addr = 0x18, -+ .platform_data = &ip7145dpf_ubicom32input_i2c_u48_platform_data, -+ }, -+ -+ /* -+ * U72, MAX7310 IOB expander, 8 bits, address 0x19 -+ */ -+ { -+ .type = "max7310", -+ .addr = 0x19, -+ .platform_data = &ip7145dpf_gpio_u72_platform_data, -+ }, -+}; -+ -+/* -+ * I2C bus on the board, SDA PE1, SCL PE2 -+ */ -+static struct i2c_gpio_platform_data ip7145dpf_i2c_data = { -+ .sda_pin = GPIO_RE_1, -+ .scl_pin = GPIO_RE_2, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+}; -+ -+static struct platform_device ip7145dpf_i2c_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip7145dpf_i2c_data, -+ }, -+}; -+ -+/****************************************************************************** -+ * Use ubicom32input driver to monitor the various pushbuttons on this board. -+ * -+ * WPS PF12 -+ * FACT_DEFAULT PF13 -+ * POWER PE4 -+ * -+ * Not sutable for the keypad buttons since those run on I2C GPIO. The polling -+ * of ubicom32input would seem to be excessive for this. -+ * -+ * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default -+ */ -+static struct ubicom32input_button ip7145dpf_ubicom32input_buttons[] = { -+ { -+ .type = EV_KEY, -+ .code = KEY_FN_F1, -+ .gpio = GPIO_RF_12, -+ .desc = "WPS", -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_FN_F2, -+ .gpio = GPIO_RF_13, -+ .desc = "Factory Default", -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_POWER, -+ .gpio = GPIO_RE_4, -+ .desc = "Power", -+ .active_low = 1, -+ }, -+}; -+ -+static struct ubicom32input_platform_data ip7145dpf_ubicom32input_data = { -+ .buttons = ip7145dpf_ubicom32input_buttons, -+ .nbuttons = ARRAY_SIZE(ip7145dpf_ubicom32input_buttons), -+}; -+ -+static struct platform_device ip7145dpf_ubicom32input_device = { -+ .name = "ubicom32input", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip7145dpf_ubicom32input_data, -+ }, -+}; -+ -+/* -+ * List of all devices in our system -+ */ -+static struct platform_device *ip7145dpf_devices[] __initdata = { -+ &ip7145dpf_i2c_device, -+ &ip7145dpf_lcdpower_device, -+ &ip7145dpf_backlight_device, -+ &ip7145dpf_ubicom32input_device, -+}; -+ -+/* -+ * ip7145dpf_power_off -+ * Called to turn the power off for this board -+ */ -+static void ip7145dpf_power_off(void) -+{ -+ gpio_set_value(GPIO_RE_5, 0); -+} -+ -+/* -+ * ip7145dpf_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip7145dpf_init(void) -+{ -+ int ret; -+ struct platform_device *audio_dev; -+ -+ ubi_gpio_init(); -+ -+#ifdef CONFIG_UIO_UBICOM32RING -+ ring_tio_init("decoder_ring"); -+#endif -+ -+ /* -+ * Start up the video driver first -+ */ -+ vdc_tio_init(); -+ -+ /* -+ * Take over holding of the power from the system -+ */ -+ ret = gpio_request(GPIO_RE_5, "power_hold"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request power hold GPIO\n", __FUNCTION__); -+ } -+ gpio_direction_output(GPIO_RE_5, 1); -+ mach_power_off = ip7145dpf_power_off; -+ -+ /* -+ * USB SEL_HOST_USB line -+ */ -+ ret = gpio_request(GPIO_RF_11, "SEL_HOST_USB"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request SEL_HOST_USB GPIO\n", __FUNCTION__); -+ } -+ gpio_direction_output(GPIO_RF_11, 0); -+ -+ /* -+ * Setup audio -+ */ -+ audio_dev = audio_device_alloc("snd-ubi32-generic", "audio", "audio-i2sout", 0); -+ if (audio_dev) { -+ platform_device_register(audio_dev); -+ } -+ -+ /* -+ * Register all of the devices we have on this board -+ */ -+ printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); -+ platform_add_devices(ip7145dpf_devices, ARRAY_SIZE(ip7145dpf_devices)); -+ -+ /* -+ * Register all of the devices which sit on the I2C bus -+ */ -+ printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); -+ i2c_register_board_info(0, ip7145dpf_i2c_board_info, ARRAY_SIZE(ip7145dpf_i2c_board_info)); -+ -+ /* -+ * We have to initialize the SPI after the I2C IOB gets setup. SPI is initialized in -+ * ip7145dpf_u72_setup -+ */ -+ -+ return 0; -+} -+ -+arch_initcall(ip7145dpf_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7160bringup.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7160bringup.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7160bringup.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7160bringup.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,134 @@ -+/* -+ * arch/ubicom32/mach-ip7k/board-ip7160bringup.c -+ * Support for the IP7160 bringup board. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#ifdef CONFIG_SERIAL_UBI32_SERDES -+#include -+#endif -+ -+/* -+ * Use ubicom32input driver to monitor the various pushbuttons on this board. -+ * -+ * WPS PD5 -+ * FACT_DEFAULT PD6 -+ * -+ * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default -+ */ -+static struct ubicom32input_button ip7160bringup_ubicom32input_buttons[] = { -+ { -+ .type = EV_KEY, -+ .code = KEY_FN_F1, -+ .gpio = GPIO_RD_5, -+ .desc = "WPS", -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_FN_F2, -+ .gpio = GPIO_RD_6, -+ .desc = "Factory Default", -+ .active_low = 1, -+ }, -+}; -+ -+static struct ubicom32input_platform_data ip7160bringup_ubicom32input_data = { -+ .buttons = ip7160bringup_ubicom32input_buttons, -+ .nbuttons = ARRAY_SIZE(ip7160bringup_ubicom32input_buttons), -+}; -+ -+static struct platform_device ip7160bringup_ubicom32input_device = { -+ .name = "ubicom32input", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip7160bringup_ubicom32input_data, -+ }, -+}; -+ -+#ifdef CONFIG_SERIAL_UBI32_SERDES -+static struct resource ip7160bringup_ubicom32_suart_resources[] = { -+ { -+ .start = RE, -+ .end = RE, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = PORT_OTHER_INT(RE), -+ .end = PORT_OTHER_INT(RE), -+ .flags = IORESOURCE_IRQ, -+ }, -+ { -+ .start = 250000000, -+ .end = 250000000, -+ .flags = UBICOM32_SUART_IORESOURCE_CLOCK, -+ }, -+}; -+ -+static struct platform_device ip7160bringup_ubicom32_suart_device = { -+ .name = "ubicom32suart", -+ .id = -1, -+ .num_resources = ARRAY_SIZE(ip7160bringup_ubicom32_suart_resources), -+ .resource = ip7160bringup_ubicom32_suart_resources, -+}; -+#endif -+ -+/* -+ * List of all devices in our system -+ */ -+static struct platform_device *ip7160bringup_devices[] __initdata = { -+#ifdef CONFIG_SERIAL_UBI32_SERDES -+ &ip7160bringup_ubicom32_suart_device, -+#endif -+ &ip7160bringup_ubicom32input_device, -+}; -+ -+/* -+ * ip7160bringup_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip7160bringup_init(void) -+{ -+ board_init(); -+ -+ ubi_gpio_init(); -+ -+ printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); -+ platform_add_devices(ip7160bringup_devices, ARRAY_SIZE(ip7160bringup_devices)); -+ -+ return 0; -+} -+ -+arch_initcall(ip7160bringup_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7160dpf.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7160dpf.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7160dpf.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7160dpf.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,326 @@ -+/* -+ * arch/ubicom32/mach-ip7k/board-ip7160dpf.c -+ * Platform initialization for ip7160dpf board. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * Backlight on the board PD0, hardware PWM -+ */ -+static const struct ubicom32hid_button ip7160dpf_ubicom32hid_buttons[] = { -+ { -+ .type = EV_KEY, -+ .code = KEY_UP, -+ .bit = 0, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_LEFT, -+ .bit = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_RIGHT, -+ .bit = 2, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_DOWN, -+ .bit = 3, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ENTER, -+ .bit = 4, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_MENU, -+ .bit = 5, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ESC, -+ .bit = 7, -+ }, -+}; -+ -+static const struct ubicom32hid_ir ip7160dpf_ubicom32hid_ircodes[] = { -+ { -+ .type = EV_KEY, -+ .code = KEY_UP, -+ .ir_code = 0xF807916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_DOWN, -+ .ir_code = 0xF20D916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_LEFT, -+ .ir_code = 0xF609916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_RIGHT, -+ .ir_code = 0xF40B916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ENTER, -+ .ir_code = 0xF50A916E -+ }, -+ { /* rotate */ -+ .type = EV_KEY, -+ .code = KEY_FN_F1, -+ .ir_code = 0xF906916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_MENU, -+ .ir_code = 0xF708916E -+ }, -+ { /* font size */ -+ .type = EV_KEY, -+ .code = KEY_FN_F2, -+ .ir_code = 0xF30C916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ESC, -+ .ir_code = 0xF10E916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_VOLUMEUP, -+ .ir_code = 0xF00F916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_VOLUMEDOWN, -+ .ir_code = 0xED12916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_MUTE, -+ .ir_code = 0xEA15916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_INFO, -+ .ir_code = 0xEF10916E -+ }, -+ { /* Like */ -+ .type = EV_KEY, -+ .code = KEY_FN_F3, -+ .ir_code = 0xEE11916E -+ }, -+ { /* Dislike */ -+ .type = EV_KEY, -+ .code = KEY_FN_F4, -+ .ir_code = 0xEB14916E -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_POWER, -+ .ir_code = 0xFD02916E -+ }, -+}; -+ -+static struct ubicom32hid_platform_data ip7160dpf_ubicom32hid_platform_data = { -+ .gpio_reset = GPIO_RI_5, -+ .gpio_reset_polarity = 0, -+ .type = UBICOM32HID_BL_TYPE_PWM, -+ .invert = 0, -+ .default_intensity = 128, -+ .buttons = ip7160dpf_ubicom32hid_buttons, -+ .nbuttons = ARRAY_SIZE(ip7160dpf_ubicom32hid_buttons), -+ .ircodes = ip7160dpf_ubicom32hid_ircodes, -+ .nircodes = ARRAY_SIZE(ip7160dpf_ubicom32hid_ircodes), -+}; -+ -+/* -+ * Devices on the I2C bus -+ * This board has a "bus 2" which is isolated from the main bus by U47 -+ * and pin RI0. It should be safe to always enable bus 2 by setting -+ * RI0 to low, however, it should be noted that on all existing configurations -+ * of this board, U49 and U51 are not populated. -+ */ -+static struct i2c_board_info __initdata ip7160dpf_i2c_board_info[] = { -+ /* -+ * U37, CS4350 DAC, address 0x4B, bus 2 -+ * THIS ENTRY MUST BE FIRST -+ */ -+ { -+ .type = "cs4350", -+ .addr = 0x4B, -+ } -+ -+ /* -+ * U24, ubicom32hid -+ */ -+ { -+ .type = "ubicom32hid", -+ .addr = 0x08, -+ .platform_data = &ip7160dpf_ubicom32hid_platform_data, -+ }, -+ -+ /* -+ * U49, ISL29001 Ambient Light Sensor, address 0x44, bus 2 (may not be stuffed) -+ */ -+ -+ /* -+ * U51, S35390A RTC, address 0x30, bus 2 (may not be stuffed) -+ */ -+#ifdef CONFIG_RTC_DRV_S35390A -+ { -+ .type = "s35390a", -+ .addr = 0x30, -+ }, -+#endif -+}; -+ -+/* -+ * I2C bus on the board, SDA PI1, SCL PI2 -+ */ -+static struct i2c_gpio_platform_data ip7160dpf_i2c_data = { -+ .sda_pin = GPIO_RI_1, -+ .scl_pin = GPIO_RI_2, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+ .scl_is_output_only = 1, -+ .udelay = 6, -+}; -+ -+static struct platform_device ip7160dpf_i2c_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip7160dpf_i2c_data, -+ }, -+}; -+ -+/* -+ * List of all devices in our system -+ */ -+static struct platform_device *ip7160dpf_devices[] __initdata = { -+ &ip7160dpf_i2c_device, -+}; -+ -+/* -+ * ip7160dpf_power_off -+ * Called to turn the power off for this board -+ */ -+static void ip7160dpf_power_off(void) -+{ -+ gpio_set_value(GPIO_RF_14, 0); -+} -+ -+/* -+ * ip7160dpf_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip7160dpf_init(void) -+{ -+ int ret; -+ struct platform_device *audio_dev; -+ -+ ubi_gpio_init(); -+ -+ /* -+ * Hold the POWER_HOLD line -+ */ -+ ret = gpio_request(GPIO_RF_14, "POWER_HOLD"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request POWER_HOLD GPIO\n", __FUNCTION__); -+ } -+ gpio_direction_output(GPIO_RF_14, 1); -+ mach_power_off = ip7160dpf_power_off; -+ -+ /* -+ * USB SEL_HOST_USB line -+ */ -+ ret = gpio_request(GPIO_RI_13, "SEL_HOST_USB"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request SEL_HOST_USB GPIO\n", __FUNCTION__); -+ } -+ gpio_direction_output(GPIO_RI_13, 0); -+ -+ /* -+ * USB/DAC nRESET line -+ */ -+ ret = gpio_request(GPIO_RI_3, "USB_DAC_nRESET"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request USB_DAC_nRESET GPIO\n", __FUNCTION__); -+ } -+ gpio_direction_output(GPIO_RI_3, 0); -+ udelay(1); -+ gpio_direction_output(GPIO_RI_3, 1); -+ -+ /* -+ * I2C BUS2 Disable line -+ */ -+ ret = gpio_request(GPIO_RI_0, "DISABLE_BUS2"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request DISABLE_BUS2 GPIO\n", __FUNCTION__); -+ } -+ gpio_direction_output(GPIO_RI_0, 0); -+ -+ vdc_tio_init(); -+ -+ printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); -+ platform_add_devices(ip7160dpf_devices, ARRAY_SIZE(ip7160dpf_devices)); -+ -+ /* -+ * Allocate the audio driver if we can -+ */ -+ audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio-i2sout", 0); -+ if (audio_dev) { -+ ip7160dpf_i2c_board_info[0].platform_data = audio_dev; -+ } -+ -+ printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); -+ i2c_register_board_info(0, ip7160dpf_i2c_board_info, ARRAY_SIZE(ip7160dpf_i2c_board_info)); -+ -+ return 0; -+} -+ -+arch_initcall(ip7160dpf_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7160rgw.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7160rgw.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7160rgw.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7160rgw.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,355 @@ -+/* -+ * arch/ubicom32/mach-ip7k/board-ip7160rgw.c -+ * Platform initialization for ip7160rgw board. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#ifdef CONFIG_SERIAL_UBI32_SERDES -+#include -+#endif -+ -+#include -+#include -+ -+#ifdef CONFIG_IP7160RGWLCD -+#include -+#include -+/* -+ * LCD Adapter board 8007-092x support -+ * -+ * Touch controller -+ * -+ * Connected via I2C bus, interrupt on PA6 -+ */ -+#include -+ -+/* -+ * ip7160rgwlcd_tsc2007_exit_platform_hw -+ */ -+static void ip7160rgwlcd_tsc2007_exit_platform_hw(void) -+{ -+ UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 17); -+ gpio_free(GPIO_RA_5); -+} -+ -+/* -+ * ip7160rgwlcd_tsc2007_init_platform_hw -+ */ -+static int ip7160rgwlcd_tsc2007_init_platform_hw(void) -+{ -+ int res = gpio_request(GPIO_RA_5, "TSC2007_IRQ"); -+ if (res) { -+ return res; -+ } -+ -+ UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 17); -+ UBICOM32_IO_PORT(RA)->ctl0 |= (0x02 << 17); -+ return 0; -+} -+ -+/* -+ * ip7160rgwlcd_tsc2007_get_pendown_state -+ */ -+static int ip7160rgwlcd_tsc2007_get_pendown_state(void) -+{ -+ return !gpio_get_value(GPIO_RA_5); -+} -+ -+static struct tsc2007_platform_data ip7160rgwlcd_tsc2007_data = { -+ .model = 2007, -+ .x_plate_ohms = 350, -+ .get_pendown_state = ip7160rgwlcd_tsc2007_get_pendown_state, -+ .init_platform_hw = ip7160rgwlcd_tsc2007_init_platform_hw, -+ .exit_platform_hw = ip7160rgwlcd_tsc2007_exit_platform_hw, -+}; -+ -+/****************************************************************************** -+ * I2C bus on the board, SDA PI14, SCL PI13 -+ */ -+static struct i2c_gpio_platform_data ip7160rgwlcd_i2c_data = { -+ .sda_pin = GPIO_RI_14, -+ .scl_pin = GPIO_RI_13, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+ .udelay = 50, -+}; -+ -+static struct platform_device ip7160rgwlcd_i2c_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip7160rgwlcd_i2c_data, -+ }, -+}; -+ -+static struct i2c_board_info __initdata ip7160rgwlcd_i2c_board_info[] = { -+ { -+ .type = "tsc2007", -+ .addr = 0x48, -+ .irq = 45, // RA5 -+ .platform_data = &ip7160rgwlcd_tsc2007_data, -+ }, -+}; -+ -+#endif -+ -+/* -+ * SPI bus over GPIO for Gigabit Ethernet Switch -+ * U58: -+ * MOSI PE0 -+ * MISO PE1 -+ * CLK PE3 -+ * CS PE2 -+ */ -+static struct ubicom32_spi_gpio_platform_data ip7160rgw_spi_gpio_data = { -+ .pin_mosi = GPIO_RE_0, -+ .pin_miso = GPIO_RE_1, -+ .pin_clk = GPIO_RE_3, -+ .bus_num = 0, // We'll call this SPI bus 0 -+ .num_chipselect = 1, // only one device on this SPI bus -+ .clk_default = 1, -+}; -+ -+static struct platform_device ip7160rgw_spi_gpio_device = { -+ .name = "ubicom32-spi-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip7160rgw_spi_gpio_data, -+ }, -+}; -+ -+static struct ubicom32_spi_gpio_controller_data ip7160rgw_bcm539x_controller_data = { -+ .pin_cs = GPIO_RE_2, -+}; -+ -+static struct switch_core_platform_data ip7160rgw_bcm539x_platform_data = { -+ .flags = SWITCH_DEV_FLAG_HW_RESET, -+ .pin_reset = GPIO_RE_4, -+ .name = "bcm539x", -+}; -+ -+static struct spi_board_info ip7160rgw_spi_board_info[] = { -+ { -+ .modalias = "bcm539x-spi", -+ .bus_num = 0, -+ .chip_select = 0, -+ .max_speed_hz = 2000000, -+ .platform_data = &ip7160rgw_bcm539x_platform_data, -+ .controller_data = &ip7160rgw_bcm539x_controller_data, -+ .mode = SPI_MODE_3, -+ } -+}; -+ -+/* -+ * LEDs -+ * -+ * WLAN1 PD0 (PWM capable) -+ * WLAN2 PD1 -+ * USB2.0 PD2 -+ * Status PD3 -+ * WPS PD4 -+ * -+ * TODO: check triggers, are they generic? -+ */ -+static struct gpio_led ip7160rgw_gpio_leds[] = { -+ { -+ .name = "d53:green:WLAN1", -+ .default_trigger = "WLAN1", -+ .gpio = GPIO_RD_0, -+ .active_low = 1, -+ }, -+ { -+ .name = "d54:green:WLAN2", -+ .default_trigger = "WLAN2", -+ .gpio = GPIO_RD_1, -+ .active_low = 1, -+ }, -+ { -+ .name = "d55:green:USB", -+ .default_trigger = "USB", -+ .gpio = GPIO_RD_2, -+ .active_low = 1, -+ }, -+ { -+ .name = "d56:green:Status", -+ .default_trigger = "Status", -+ .gpio = GPIO_RD_3, -+ .active_low = 1, -+ }, -+ { -+ .name = "d57:green:WPS", -+ .default_trigger = "WPS", -+ .gpio = GPIO_RD_4, -+ .active_low = 1, -+ }, -+}; -+ -+static struct gpio_led_platform_data ip7160rgw_gpio_led_platform_data = { -+ .num_leds = 5, -+ .leds = ip7160rgw_gpio_leds, -+}; -+ -+static struct platform_device ip7160rgw_gpio_leds_device = { -+ .name = "leds-gpio", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip7160rgw_gpio_led_platform_data, -+ }, -+}; -+ -+/* -+ * Use ubicom32input driver to monitor the various pushbuttons on this board. -+ * -+ * WPS PD5 -+ * FACT_DEFAULT PD6 -+ * -+ * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default -+ */ -+static struct ubicom32input_button ip7160rgw_ubicom32input_buttons[] = { -+ { -+ .type = EV_KEY, -+ .code = KEY_FN_F1, -+ .gpio = GPIO_RD_5, -+ .desc = "WPS", -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_FN_F2, -+ .gpio = GPIO_RD_6, -+ .desc = "Factory Default", -+ .active_low = 1, -+ }, -+}; -+ -+static struct ubicom32input_platform_data ip7160rgw_ubicom32input_data = { -+ .buttons = ip7160rgw_ubicom32input_buttons, -+ .nbuttons = ARRAY_SIZE(ip7160rgw_ubicom32input_buttons), -+}; -+ -+static struct platform_device ip7160rgw_ubicom32input_device = { -+ .name = "ubicom32input", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip7160rgw_ubicom32input_data, -+ }, -+}; -+ -+#ifdef CONFIG_SERIAL_UBI32_SERDES -+static struct resource ip7160rgw_ubicom32_suart_resources[] = { -+ { -+ .start = RE, -+ .end = RE, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = PORT_OTHER_INT(RE), -+ .end = PORT_OTHER_INT(RE), -+ .flags = IORESOURCE_IRQ, -+ }, -+ { -+ .start = 250000000, -+ .end = 250000000, -+ .flags = UBICOM32_SUART_IORESOURCE_CLOCK, -+ }, -+}; -+ -+static struct platform_device ip7160rgw_ubicom32_suart_device = { -+ .name = "ubicom32suart", -+ .id = -1, -+ .num_resources = ARRAY_SIZE(ip7160rgw_ubicom32_suart_resources), -+ .resource = ip7160rgw_ubicom32_suart_resources, -+}; -+#endif -+ -+/* -+ * List of all devices in our system -+ */ -+static struct platform_device *ip7160rgw_devices[] __initdata = { -+#ifdef CONFIG_SERIAL_UBI32_SERDES -+ &ip7160rgw_ubicom32_suart_device, -+#endif -+ &ip7160rgw_ubicom32input_device, -+ &ip7160rgw_gpio_leds_device, -+ &ip7160rgw_spi_gpio_device, -+#ifdef CONFIG_IP7160RGWLCD -+ &ip7160rgwlcd_i2c_device, -+#endif -+}; -+ -+/* -+ * ip7160rgw_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip7160rgw_init(void) -+{ -+ board_init(); -+ -+ /* -+ * Rev 1.2 boards have spi in a different place than 1.1/1.0 -+ */ -+ if (strcmp(board_get_revision(), "1.2") == 0) { -+ ip7160rgw_spi_gpio_data.pin_mosi = GPIO_RD_7; -+ } -+ -+ ubi_gpio_init(); -+ -+ /* -+ * Reserve switch SPI CS on behalf on switch driver -+ */ -+ if (gpio_request(ip7160rgw_bcm539x_controller_data.pin_cs, "switch-bcm539x-cs")) { -+ printk(KERN_WARNING "Could not request cs of switch SPI I/F\n"); -+ return -EIO; -+ } -+ gpio_direction_output(ip7160rgw_bcm539x_controller_data.pin_cs, 1); -+ -+ printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); -+ platform_add_devices(ip7160rgw_devices, ARRAY_SIZE(ip7160rgw_devices)); -+ -+ printk(KERN_INFO "%s: registering SPI resources\n", __FUNCTION__); -+ spi_register_board_info(ip7160rgw_spi_board_info, ARRAY_SIZE(ip7160rgw_spi_board_info)); -+ -+#ifdef CONFIG_IP7160RGWLCD -+ printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); -+ i2c_register_board_info(0, ip7160rgwlcd_i2c_board_info, ARRAY_SIZE(ip7160rgwlcd_i2c_board_info)); -+ printk(KERN_INFO "IP7160 RGW + LCD\n"); -+#else -+ printk(KERN_INFO "IP7160 RGW\n"); -+#endif -+ return 0; -+} -+ -+arch_initcall(ip7160rgw_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500av.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500av.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500av.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500av.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,273 @@ -+/* -+ * arch/ubicom32/mach-ip7k/board-ip7500av.c -+ * Support for IP7500 Audio Video Board + CPU module board. -+ * -+ * This file supports the IP7500 Audio Video Board: -+ * 8007-0810 Rev 1.0 -+ * with one of the following CPU module boards: -+ * 8007-0510 Rev 1.0 -+ * 8007-0510A Rev 1.0 (with ethernet) -+ * -+ * DIP Switch SW2 configuration: (*) default -+ * POS 1: on(*) = PCI enabled, off = PCI disabled -+ * POS 2: on(*) = TTYX => PA6, off = TTYX => PF12 -+ * POS 3: on(*) = TTYY => PA7, off = TTYY => PF15 -+ * POS 4: unused -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/****************************************************************************** -+ * Devices on the I2C bus -+ * -+ * BEWARE of changing the order of things in this array as we depend on -+ * certain things to be in certain places. -+ */ -+static struct i2c_board_info __initdata ip7500av_i2c_board_info[] = { -+ /* -+ * U6, CS4384 DAC, address 0x19 -+ */ -+ { -+ .type = "cs4384", -+ .addr = 0x19, -+ }, -+}; -+ -+/* -+ * I2C bus on the board, SDA PD1, SCL PD2 -+ */ -+static struct i2c_gpio_platform_data ip7500av_i2c_data = { -+ .sda_pin = GPIO_RD_6, -+ .scl_pin = GPIO_RD_3, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+ .udelay = 50, -+}; -+ -+static struct platform_device ip7500av_i2c_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip7500av_i2c_data, -+ }, -+}; -+ -+/* -+ * List of possible mclks we can generate. This depends on the CPU frequency. -+ */ -+static struct ubi32_cs4384_mclk_entry ip7500av_cs4384_mclk_entries[] = { -+ { -+ .rate = 12288000, -+ .div = 44, -+ }, -+ { -+ .rate = 11289600, -+ .div = 48, -+ }, -+}; -+ -+/* -+ * List of all devices in our system -+ */ -+static struct platform_device *ip7500av_devices[] __initdata = { -+ &ip7500av_i2c_device, -+}; -+ -+/* -+ * ip7500av_vdac_write -+ */ -+static int __init ip7500av_vdac_write(int reg, int val) -+{ -+ struct i2c_adapter *adap; -+ struct i2c_msg msg[1]; -+ unsigned char data[2]; -+ int err; -+ -+ adap = i2c_get_adapter(0); -+ if (!adap) { -+ printk(KERN_WARNING "%s: failed to get i2c adapter\n", __FUNCTION__); -+ return -ENODEV; -+ } -+ msg->addr = 0x2B; -+ msg->flags = 0; -+ msg->len = 2; -+ msg->buf = data; -+ data[0] = reg; -+ data[1] = val; -+ err = i2c_transfer(adap, msg, 1); -+ i2c_put_adapter(adap); -+ if (err >= 0) { -+ return 0; -+ } -+ return err; -+} -+ -+/* -+ * ip7500av_vdac_init -+ * Initializes the video DAC via I2C -+ * -+ * Equivalent mode line: 720x480p = 27 Mhz, 720 736 800 858 480 484 492 525 -+ */ -+static int __init ip7500av_vdac_init(void) -+{ -+ int err; -+ -+ printk(KERN_INFO "Initializing ADV7393 DAC\n"); -+ -+ /* -+ * Reset the VDAC -+ */ -+ if (gpio_request(GPIO_RF_6, "VDAC Reset")) { -+ printk(KERN_WARNING "%s: failed to allocate VDAC Reset\n", __FUNCTION__); -+ return -EBUSY; -+ } -+ gpio_direction_output(GPIO_RF_6, 0); -+ udelay(1); -+ gpio_set_value(GPIO_RF_6, 1); -+ -+ /* -+ * See table 100 of ADV7393 data sheet: 16-bit 525p YCrCb In, YPbPr Out -+ */ -+ err = ip7500av_vdac_write(0x17, 0x02); -+ if (err) { -+ printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); -+ return err; -+ } -+ err = ip7500av_vdac_write(0x00, 0x1c); -+ if (err) { -+ printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); -+ return err; -+ } -+ err = ip7500av_vdac_write(0x01, 0x10); -+ if (err) { -+ printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); -+ return err; -+ } -+ err = ip7500av_vdac_write(0x31, 0x01); -+ if (err) { -+ printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); -+ return err; -+ } -+#ifdef IP7500AV_VDAC_SWAP_PBPR -+ err = ip7500av_vdac_write(0x35, 0x08); -+ if (err) { -+ printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); -+ return err; -+ } -+#endif -+#ifdef IP7500AV_VDAC_FULL_RANGE -+ err = ip7500av_vdac_write(0x30, 0x02); -+ if (err) { -+ printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__); -+ return err; -+ } -+#endif -+ return 0; -+} -+late_initcall(ip7500av_vdac_init); -+ -+/* -+ * ip7500av_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip7500av_init(void) -+{ -+ struct platform_device *audio_dev; -+ struct platform_device *audio_dev2; -+ struct ubi32_cs4384_platform_data *cs4384_pd; -+ -+ board_init(); -+ -+ ubi_gpio_init(); -+ -+ vdc_tio_init(); -+ -+ printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); -+ platform_add_devices(ip7500av_devices, ARRAY_SIZE(ip7500av_devices)); -+ -+ /* -+ * CS4384 DAC -+ */ -+ audio_dev = audio_device_alloc("snd-ubi32-cs4384", "audio", "audio-i2sout", -+ sizeof(struct ubi32_cs4384_platform_data)); -+ if (audio_dev) { -+ /* -+ * Attempt to figure out a good divisor. This will only work -+ * assuming the core frequency is compatible. -+ */ -+ int i; -+ unsigned int freq = processor_frequency(); -+ for (i = 0; i < ARRAY_SIZE(ip7500av_cs4384_mclk_entries); i++) { -+ unsigned int div; -+ unsigned int rate = ip7500av_cs4384_mclk_entries[i].rate / 1000; -+ div = ((freq / rate) + 500) / 1000; -+ ip7500av_cs4384_mclk_entries[i].div = div; -+ printk("CS4384 mclk %d rate %u000Hz div %u act %u\n", i, rate, div, freq / div); -+ } -+ -+ cs4384_pd = audio_device_priv(audio_dev); -+ cs4384_pd->mclk_src = UBI32_CS4384_MCLK_PWM_0; -+ cs4384_pd->n_mclk = ARRAY_SIZE(ip7500av_cs4384_mclk_entries); -+ cs4384_pd->mclk_entries = ip7500av_cs4384_mclk_entries; -+ ip7500av_i2c_board_info[0].platform_data = audio_dev; -+ -+ /* -+ * Reset the DAC -+ */ -+ if (gpio_request(GPIO_RF_4, "DAC Reset") == 0) { -+ gpio_direction_output(GPIO_RF_4, 0); -+ udelay(1); -+ gpio_direction_output(GPIO_RF_4, 1); -+ } else { -+ printk("Unable to request DAC reset GPIO\n"); -+ } -+ } -+ -+ /* -+ * SPDIF port -+ */ -+ audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0); -+ if (audio_dev2) { -+ platform_device_register(audio_dev2); -+ } -+ -+ /* -+ * Register all of the devices which sit on the I2C bus -+ */ -+ printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); -+ i2c_register_board_info(0, ip7500av_i2c_board_info, ARRAY_SIZE(ip7500av_i2c_board_info)); -+ -+ printk(KERN_INFO "IP7500 Audio/Video Board\n"); -+ return 0; -+} -+arch_initcall(ip7500av_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500iap.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500iap.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500iap.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500iap.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,414 @@ -+/* -+ * arch/ubicom32/mach-ip7k/board-ip7500iap.c -+ * Support for IP7500 Internet Audio Player -+ * -+ * This file supports the IP7500 Internet Audio Player: -+ * 8007-1110 Rev 1.0 -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+#include -+ -+/****************************************************************************** -+ * SD/IO Port F (Slot 1) platform data -+ */ -+static struct resource ip7500iap_portf_sd_resources[] = { -+ /* -+ * Send IRQ -+ */ -+ [0] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Receive IRQ -+ */ -+ [1] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Memory Mapped Registers -+ */ -+ [2] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+static struct ubicom32sd_card ip7500iap_portf_sd_cards[] = { -+ [0] = { -+ .pin_wp = GPIO_RF_7, -+ .wp_polarity = 1, -+ .pin_pwr = GPIO_RF_8, -+ .pin_cd = GPIO_RF_6, -+ }, -+}; -+ -+static struct ubicom32sd_platform_data ip7500iap_portf_sd_platform_data = { -+ .ncards = 1, -+ .cards = ip7500iap_portf_sd_cards, -+}; -+ -+static struct platform_device ip7500iap_portf_sd_device = { -+ .name = "ubicom32sd", -+ .id = 0, -+ .resource = ip7500iap_portf_sd_resources, -+ .num_resources = ARRAY_SIZE(ip7500iap_portf_sd_resources), -+ .dev = { -+ .platform_data = &ip7500iap_portf_sd_platform_data, -+ }, -+ -+}; -+ -+/* -+ * ip7500iap_portf_sd_init -+ */ -+static void ip7500iap_portf_sd_init(void) -+{ -+ /* -+ * Check the device tree for the sd_tio -+ */ -+ struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd"); -+ if (!sd_node) { -+ printk(KERN_INFO "PortF SDTIO not found\n"); -+ return; -+ } -+ -+ /* -+ * Fill in the resources and platform data from devtree information -+ */ -+ ip7500iap_portf_sd_resources[0].start = sd_node->dn.sendirq; -+ ip7500iap_portf_sd_resources[1].start = sd_node->dn.recvirq; -+ ip7500iap_portf_sd_resources[2].start = (u32_t)&(sd_node->regs); -+ ip7500iap_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); -+ -+ platform_device_register(&ip7500iap_portf_sd_device); -+} -+ -+/****************************************************************************** -+ * SD/IO Port B (Slot 2) platform data -+ */ -+static struct resource ip7500iap_portb_sd_resources[] = { -+ /* -+ * Send IRQ -+ */ -+ [0] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Receive IRQ -+ */ -+ [1] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Memory Mapped Registers -+ */ -+ [2] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+static struct ubicom32sd_card ip7500iap_portb_sd_cards[] = { -+ [0] = { -+ .pin_wp = GPIO_RB_13, -+ .wp_polarity = 1, -+ .pin_pwr = GPIO_RB_11, -+ .pin_cd = GPIO_RB_12, -+ }, -+}; -+ -+static struct ubicom32sd_platform_data ip7500iap_portb_sd_platform_data = { -+ .ncards = 1, -+ .cards = ip7500iap_portb_sd_cards, -+}; -+ -+static struct platform_device ip7500iap_portb_sd_device = { -+ .name = "ubicom32sd", -+ .id = 1, -+ .resource = ip7500iap_portb_sd_resources, -+ .num_resources = ARRAY_SIZE(ip7500iap_portb_sd_resources), -+ .dev = { -+ .platform_data = &ip7500iap_portb_sd_platform_data, -+ }, -+ -+}; -+ -+/* -+ * ip7500iap_portb_sd_init -+ */ -+static void ip7500iap_portb_sd_init(void) -+{ -+ /* -+ * Check the device tree for the sd_tio -+ */ -+ struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd"); -+ if (!sd_node) { -+ printk(KERN_INFO "PortB SDTIO not found\n"); -+ return; -+ } -+ -+ /* -+ * Fill in the resources and platform data from devtree information -+ */ -+ ip7500iap_portb_sd_resources[0].start = sd_node->dn.sendirq; -+ ip7500iap_portb_sd_resources[1].start = sd_node->dn.recvirq; -+ ip7500iap_portb_sd_resources[2].start = (u32_t)&(sd_node->regs); -+ ip7500iap_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); -+ -+ platform_device_register(&ip7500iap_portb_sd_device); -+} -+ -+/****************************************************************************** -+ * Touch controller -+ * -+ * Connected via I2C bus, interrupt on PA6 -+ */ -+#include -+ -+/* -+ * ip7500iap_tsc2007_exit_platform_hw -+ */ -+static void ip7500iap_tsc2007_exit_platform_hw(void) -+{ -+ UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 19); -+ gpio_free(GPIO_RA_6); -+} -+ -+/* -+ * ip7500iap_tsc2007_init_platform_hw -+ */ -+static int ip7500iap_tsc2007_init_platform_hw(void) -+{ -+ int res = gpio_request(GPIO_RA_6, "TSC2007_IRQ"); -+ if (res) { -+ return res; -+ } -+ -+ UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 19); -+ UBICOM32_IO_PORT(RA)->ctl0 |= (0x02 << 19); -+ return 0; -+} -+ -+/* -+ * ip7500iap_tsc2007_get_pendown_state -+ */ -+static int ip7500iap_tsc2007_get_pendown_state(void) -+{ -+ return !gpio_get_value(GPIO_RA_6); -+} -+ -+static struct tsc2007_platform_data ip7500iap_tsc2007_data = { -+ .model = 2007, -+ .x_plate_ohms = 350, -+ .get_pendown_state = ip7500iap_tsc2007_get_pendown_state, -+ .init_platform_hw = ip7500iap_tsc2007_init_platform_hw, -+ .exit_platform_hw = ip7500iap_tsc2007_exit_platform_hw, -+}; -+ -+/****************************************************************************** -+ * i2c devices -+ * -+ * DO NOT CHANGE THE ORDER HERE unless you know how this works. There -+ * are hardcoded indicies which refer to the order of drivers listed here. -+ */ -+static struct i2c_board_info __initdata ip7500iap_i2c_board_info[] = { -+ /* -+ * U6, CS4350 DAC, address 0x4B -+ */ -+ { -+ .type = "cs4350", -+ .addr = 0x4B, -+ }, -+ -+ /* -+ * U20, S35390A RTC, address 0x30 -+ */ -+ { -+ .type = "s35390a", -+ .addr = 0x30, -+ }, -+ -+ /* -+ * U9, TSC2007 Touch screen controller, address 0x49, irq RA6 -+ */ -+ { -+ .type = "tsc2007", -+ .addr = 0x49, -+ .irq = 46, -+ .platform_data = &ip7500iap_tsc2007_data, -+ }, -+}; -+ -+/* -+ * I2C bus on the board, SDA PE4, SCL PE5 -+ */ -+static struct i2c_gpio_platform_data ip7500iap_i2c_data = { -+ .sda_pin = GPIO_RF_14, -+ .scl_pin = GPIO_RF_13, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+ .udelay = 50, -+}; -+ -+static struct platform_device ip7500iap_i2c_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip7500iap_i2c_data, -+ }, -+}; -+ -+/****************************************************************************** -+ * Backlight on the board PD0, hardware PWM -+ */ -+static struct ubicom32bl_platform_data ip7500iap_backlight_data = { -+ .type = UBICOM32BL_TYPE_PWM, -+ .pwm_channel = 2, -+ .pwm_prescale = 15, -+ .pwm_period = 60, -+ .default_intensity = 0x80, -+}; -+ -+static struct platform_device ip7500iap_backlight_device = { -+ .name = "ubicom32bl", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip7500iap_backlight_data, -+ }, -+}; -+ -+/****************************************************************************** -+ * Devices on this board -+ */ -+static struct platform_device *ip7500iap_devices[] __initdata = { -+ &ip7500iap_i2c_device, -+ &ip7500iap_backlight_device, -+}; -+ -+/* -+ * ip7500iap_power_off -+ * Called to turn the power off for this board -+ */ -+static void ip7500iap_power_off(void) -+{ -+ gpio_set_value(GPIO_RF_11, 0); -+} -+ -+/* -+ * ip7500iap_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip7500iap_init(void) -+{ -+ struct platform_device *audio_dev; -+ struct platform_device *audio_dev2; -+ int ret; -+ -+ board_init(); -+ -+ ubi_gpio_init(); -+ -+ /* -+ * Hold the POWER_HOLD line -+ */ -+ ret = gpio_request(GPIO_RF_11, "POWER_HOLD"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request POWER_HOLD GPIO\n", __FUNCTION__); -+ } -+ gpio_direction_output(GPIO_RF_11, 1); -+ mach_power_off = ip7500iap_power_off; -+ -+ /* -+ * DAC nRESET line -+ */ -+ ret = gpio_request(GPIO_RE_7, "DAC_nRESET"); -+ if (ret) { -+ printk(KERN_ERR "%s: could not request DAC_nRESET GPIO\n", __FUNCTION__); -+ } -+ gpio_direction_output(GPIO_RE_7, 0); -+ udelay(1); -+ gpio_set_value(GPIO_RE_7, 1); -+ -+ /* -+ * Bring up any SDIO slots -+ */ -+ ip7500iap_portb_sd_init(); -+ ip7500iap_portf_sd_init(); -+ -+ /* -+ * Bring up audio devices -+ */ -+ platform_add_devices(ip7500iap_devices, ARRAY_SIZE(ip7500iap_devices)); -+ -+ audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0); -+ if (audio_dev) { -+ ip7500iap_i2c_board_info[0].platform_data = audio_dev; -+ } -+ -+ audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0); -+ if (audio_dev2) { -+ platform_device_register(audio_dev2); -+ } -+ -+ printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); -+ i2c_register_board_info(0, ip7500iap_i2c_board_info, ARRAY_SIZE(ip7500iap_i2c_board_info)); -+ -+ printk(KERN_INFO "IP7500 Internet Audio Player\n"); -+ -+ return 0; -+} -+ -+arch_initcall(ip7500iap_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500media.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500media.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500media.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500media.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,732 @@ -+/* -+ * arch/ubicom32/mach-ip7k/board-ip7500media.c -+ * Board file for IP7500 media board. -+ * -+ * Supports the following configuration -+ * CPU Module: -+ * P/N 8007-0510 rev 1.0 NOPHY -+ * P/N 8007-0511 rev 1.1 NOPHY -+ * DIP Switch SW2 configuration: -+ * POS 1: on = PCI enabled -+ * POS 2: off = TTYX => PF12 -+ * POS 3: off = TTYY => PF15 -+ * POS 4: unused -+ * Media Board: -+ * P/N 8007-0610 rev 1.0 -+ * -+ * LCD Adapter Board: (optional) -+ * P/N 8007-0920 rev 2.0 -+ * P/N 8007-0921 rev 2.1 -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+/****************************************************************************** -+ * SD/IO Port F (Slot 1) platform data -+ */ -+static struct resource ip7500media_portf_sd_resources[] = { -+ /* -+ * Send IRQ -+ */ -+ [0] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Receive IRQ -+ */ -+ [1] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Memory Mapped Registers -+ */ -+ [2] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+static struct ubicom32sd_card ip7500media_portf_sd_cards[] = { -+ [0] = { -+ .pin_wp = IP7500MEDIA_IO16, -+ .wp_polarity = 1, -+ .pin_pwr = IP7500MEDIA_IO20, -+ .pin_cd = IP7500MEDIA_IO23, -+ }, -+ [1] = { -+ .pin_wp = IP7500MEDIA_IO17, -+ .wp_polarity = 1, -+ .pin_pwr = IP7500MEDIA_IO21, -+ .pin_cd = IP7500MEDIA_IO24, -+ }, -+}; -+ -+static struct ubicom32sd_platform_data ip7500media_portf_sd_platform_data = { -+ .ncards = 2, -+ .cards = ip7500media_portf_sd_cards, -+}; -+ -+static struct platform_device ip7500media_portf_sd_device = { -+ .name = "ubicom32sd", -+ .id = 0, -+ .resource = ip7500media_portf_sd_resources, -+ .num_resources = ARRAY_SIZE(ip7500media_portf_sd_resources), -+ .dev = { -+ .platform_data = &ip7500media_portf_sd_platform_data, -+ }, -+ -+}; -+ -+/* -+ * ip7500media_portf_sd_init -+ */ -+static void ip7500media_portf_sd_init(void) -+{ -+ /* -+ * Check the device tree for the sd_tio -+ */ -+ struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd"); -+ if (!sd_node) { -+ printk(KERN_INFO "PortF SDTIO not found\n"); -+ return; -+ } -+ -+ /* -+ * Fill in the resources and platform data from devtree information -+ */ -+ ip7500media_portf_sd_resources[0].start = sd_node->dn.sendirq; -+ ip7500media_portf_sd_resources[1].start = sd_node->dn.recvirq; -+ ip7500media_portf_sd_resources[2].start = (u32_t)&(sd_node->regs); -+ ip7500media_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); -+ -+ platform_device_register(&ip7500media_portf_sd_device); -+} -+ -+/****************************************************************************** -+ * SD/IO Port B (Slot 2) platform data -+ */ -+static struct resource ip7500media_portb_sd_resources[] = { -+ /* -+ * Send IRQ -+ */ -+ [0] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Receive IRQ -+ */ -+ [1] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_IRQ, -+ }, -+ -+ /* -+ * Memory Mapped Registers -+ */ -+ [2] = { -+ /* -+ * The init routine will query the devtree and fill this in -+ */ -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+static struct ubicom32sd_card ip7500media_portb_sd_cards[] = { -+ [0] = { -+ .pin_wp = IP7500MEDIA_IO19, -+ .wp_polarity = 1, -+ .pin_pwr = IP7500MEDIA_IO22, -+ .pin_cd = IP7500MEDIA_IO18, -+ }, -+}; -+ -+static struct ubicom32sd_platform_data ip7500media_portb_sd_platform_data = { -+ .ncards = 1, -+ .cards = ip7500media_portb_sd_cards, -+}; -+ -+static struct platform_device ip7500media_portb_sd_device = { -+ .name = "ubicom32sd", -+ .id = 1, -+ .resource = ip7500media_portb_sd_resources, -+ .num_resources = ARRAY_SIZE(ip7500media_portb_sd_resources), -+ .dev = { -+ .platform_data = &ip7500media_portb_sd_platform_data, -+ }, -+ -+}; -+ -+/* -+ * ip7500media_portb_sd_init -+ */ -+static void ip7500media_portb_sd_init(void) -+{ -+ /* -+ * Check the device tree for the sd_tio -+ */ -+ struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd"); -+ if (!sd_node) { -+ printk(KERN_INFO "PortB SDTIO not found\n"); -+ return; -+ } -+ -+ /* -+ * Fill in the resources and platform data from devtree information -+ */ -+ ip7500media_portb_sd_resources[0].start = sd_node->dn.sendirq; -+ ip7500media_portb_sd_resources[1].start = sd_node->dn.recvirq; -+ ip7500media_portb_sd_resources[2].start = (u32_t)&(sd_node->regs); -+ ip7500media_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs); -+ -+ platform_device_register(&ip7500media_portb_sd_device); -+} -+ -+/* -+ * ip7500media_u17_setup -+ * Called by I2C to tell us that u17 is setup. -+ * -+ * This function is called by I2C to tell us that u17 has been setup. All -+ * devices which rely on this chip being initialized (or even present) need to -+ * be initialized in this function otherwise they may get initialized too early. -+ * -+ * Currently the only device depending on u17 is the SDIO -+ */ -+static int __init ip7500media_u17_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *context) -+{ -+ /* -+ * Initialize the Port F/Port B SD slots (only the enabled ports will init) -+ */ -+ ip7500media_portf_sd_init(); -+ ip7500media_portb_sd_init(); -+ -+ return 0; -+} -+ -+/****************************************************************************** -+ * LCD VGH on the board at PE6 -+ */ -+static struct ubicom32lcdpower_platform_data ip7500media_lcdpower_data = { -+ .vgh_gpio = GPIO_RE_7, -+ .vgh_polarity = true, -+}; -+ -+static struct platform_device ip7500media_lcdpower_device = { -+ .name = "ubicom32lcdpower", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip7500media_lcdpower_data, -+ }, -+}; -+ -+/****************************************************************************** -+ * Backlight on the board PD0, hardware PWM -+ */ -+static struct ubicom32bl_platform_data ip7500media_backlight_data = { -+ .type = UBICOM32BL_TYPE_PWM, -+ .pwm_channel = 2, -+ .pwm_prescale = 15, -+ .pwm_period = 60, -+ .default_intensity = 0x80, -+}; -+ -+static struct platform_device ip7500media_backlight_device = { -+ .name = "ubicom32bl", -+ .id = -1, -+ .dev = { -+ .platform_data = &ip7500media_backlight_data, -+ }, -+}; -+ -+/****************************************************************************** -+ * Ubicom32Input on I2C, U15 MAX7310, address 0x18, 8 bits -+ */ -+static struct ubicom32input_i2c_button ip7500media_ubicom32input_i2c_u15_buttons[] = { -+ { -+ .type = EV_KEY, -+ .code = KEY_LEFT, -+ .bit = 0, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_RIGHT, -+ .bit = 1, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_UP, -+ .bit = 2, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_DOWN, -+ .bit = 3, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ENTER, -+ .bit = 4, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_MENU, -+ .bit = 5, -+ .active_low = 1, -+ }, -+ { -+ .type = EV_KEY, -+ .code = KEY_ESC, -+ .bit = 6, -+ .active_low = 1, -+ }, -+}; -+ -+static struct ubicom32input_i2c_platform_data ip7500media_ubicom32input_i2c_u15_platform_data = { -+ .buttons = ip7500media_ubicom32input_i2c_u15_buttons, -+ .nbuttons = ARRAY_SIZE(ip7500media_ubicom32input_i2c_u15_buttons), -+ .name = "Ubicom32 Input I2C U15", -+}; -+ -+/****************************************************************************** -+ * Additional GPIO chips -+ */ -+static struct pca953x_platform_data ip7500media_gpio_u16_platform_data = { -+ .gpio_base = IP7500MEDIA_U16_BASE, -+}; -+ -+static struct pca953x_platform_data ip7500media_gpio_u17_platform_data = { -+ .gpio_base = IP7500MEDIA_U17_BASE, -+ .setup = ip7500media_u17_setup, -+}; -+ -+static struct pca953x_platform_data ip7500media_gpio_u18_platform_data = { -+ .gpio_base = IP7500MEDIA_U18_BASE, -+}; -+ -+ -+/****************************************************************************** -+ * Touch controller present on LCD Adapter board -+ * -+ * Connected via I2C bus, interrupt on PD1 -+ */ -+#include -+ -+/* -+ * ip7500media_tsc2007_exit_platform_hw -+ */ -+static void ip7500media_tsc2007_exit_platform_hw(void) -+{ -+ UBICOM32_IO_PORT(RD)->int_mask &= ~(1 << 11); -+ UBICOM32_IO_PORT(RD)->ctl2 &= ~(0x03 << 16); -+ gpio_free(GPIO_RD_1); -+} -+ -+/* -+ * ip7500media_tsc2007_init_platform_hw -+ */ -+static int ip7500media_tsc2007_init_platform_hw(void) -+{ -+ int res = gpio_request(GPIO_RD_1, "TSC2007_IRQ"); -+ if (res) { -+ return res; -+ } -+ UBICOM32_IO_PORT(RD)->function = 0; -+ UBICOM32_IO_PORT(RD)->int_mask = (1 << 11); -+ UBICOM32_IO_PORT(RD)->ctl2 &= ~(0x03 << 16); -+ UBICOM32_IO_PORT(RD)->ctl2 |= (0x02 << 16); -+ -+ return 0; -+} -+ -+/* -+ * ip7500media_tsc2007_clear_penirq -+ */ -+static void ip7500media_tsc2007_clear_penirq(void) -+{ -+ UBICOM32_IO_PORT(RD)->int_clr = (1 << 11); -+} -+ -+/* -+ * ip7500media_tsc2007_get_pendown_state -+ */ -+static int ip7500media_tsc2007_get_pendown_state(void) -+{ -+ return !gpio_get_value(GPIO_RD_1); -+} -+ -+static struct tsc2007_platform_data ip7500media_tsc2007_data = { -+ .model = 2007, -+ .x_plate_ohms = 350, -+ .get_pendown_state = ip7500media_tsc2007_get_pendown_state, -+ .init_platform_hw = ip7500media_tsc2007_init_platform_hw, -+ .exit_platform_hw = ip7500media_tsc2007_exit_platform_hw, -+ .clear_penirq = ip7500media_tsc2007_clear_penirq, -+}; -+ -+/****************************************************************************** -+ * Devices on the I2C bus -+ * -+ * BEWARE of changing the order of things in this array as we depend on -+ * certain things to be in certain places. -+ */ -+static struct i2c_board_info __initdata ip7500media_i2c_board_info[] = { -+ /* -+ * U6, CS4350 DAC, address 0x4B -+ */ -+ { -+ .type = "cs4350", -+ .addr = 0x4B, -+ }, -+ -+ /* -+ * U14, S35390A RTC, address 0x30 -+ */ -+ { -+ .type = "s35390a", -+ .addr = 0x30, -+ }, -+ -+ /* -+ * U15, MAX7310 IO expander, 8 bits, address 0x18 -+ * IO0: User I/O (J16-1) (Left) IO4: User I/O (J16-5) (Enter) -+ * IO1: User I/O (J16-2) (Right) IO5: User I/O (J16-6) (Menu) -+ * IO2: User I/O (J16-3) (Up) IO6: User I/O (J16-7) (Back) -+ * IO3: User I/O (J16-4) (Down) IO7: User I/O (J16-8) -+ */ -+ { -+ .type = "ubicom32in_max7310", -+ .addr = 0x18, -+ .platform_data = &ip7500media_ubicom32input_i2c_u15_platform_data, -+ }, -+ -+ /* -+ * U16, MAX7310 IO expander, 8 bits, address 0x1C -+ * IO8 : User I/O (J16-9) IO12: User I/O (J16-17) -+ * IO9 : User I/O (J16-10) IO13: User I/O (J16-18) -+ * IO10: User I/O (J16-15) IO14: User I/O (J16-19) -+ * IO11: User I/O (J16-16) IO15: User I/O (J16-20) -+ */ -+ { -+ .type = "max7310", -+ .addr = 0x1C, -+ .platform_data = &ip7500media_gpio_u16_platform_data, -+ }, -+ -+ /* -+ * U17, MAX7310 IO expander, 8 bits, address 0x1A -+ * IO16: SDIO1A_WP IO20: SD1A_PWREN -+ * IO17: SDIO1B_WP IO21: SD1B_PWREN -+ * IO18: SDIO2_CD IO22: SD2_PWREN -+ * IO19: SDIO2_WP IO23: SDIO1A_CD -+ * -+ */ -+ { -+ .type = "max7310", -+ .addr = 0x1A, -+ .platform_data = &ip7500media_gpio_u17_platform_data, -+ }, -+ -+ /* -+ * U18, MAX7310 IOB expander, 8 bits, address 0x1E -+ * IO24: SDIO1B_CD IO28: User I/O TP6 -+ * IO25: User I/O TP9 IO29: User I/O TP5 -+ * IO26: User I/O TP8 IO30: User I/O TP4 -+ * IO27: User I/O TP7 IO31: User I/O TP3 -+ */ -+ { -+ .type = "max7310", -+ .addr = 0x1E, -+ .platform_data = &ip7500media_gpio_u18_platform_data, -+ }, -+}; -+ -+/* -+ * Additional I2C devices to add when a LCD adapter board is present -+ */ -+static struct i2c_board_info __initdata ip7500media_lcd_adapter_i2c_board_info[] = { -+ { -+ I2C_BOARD_INFO("tsc2007", 0x48), -+ .irq = PORT_OTHER_INT(RD), -+ .platform_data = &ip7500media_tsc2007_data, -+ }, -+}; -+ -+/* -+ * I2C bus on the board, SDA PE4, SCL PE5 -+ */ -+static struct i2c_gpio_platform_data ip7500media_i2c_data = { -+ .sda_pin = GPIO_RE_4, -+ .scl_pin = GPIO_RE_5, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+ .udelay = 50, -+}; -+ -+static struct platform_device ip7500media_i2c_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip7500media_i2c_data, -+ }, -+}; -+ -+/* -+ * Virtual Frame Buffer device for use with LCD Adapter -+ */ -+static struct platform_device ip7500media_vfb_device = { -+ .name = "ubicom32vfb", -+ .id = -1, -+}; -+ -+/* -+ * vdc_override: -+ * 0: no override (auto-detect) -+ * 1: force vdc usage -+ * 2: force lcd adapter usage -+ */ -+static int __initdata vdc_override = 0; -+ -+/* -+ * ip7500media_set_forcevdc -+ * Called when forcevdc is present on the kernel boot line -+ */ -+static int __init ip7500media_set_forcevdc(char *str) -+{ -+ if (str[0] == '1') { -+ vdc_override = 1; -+ } else { -+ vdc_override = 2; -+ } -+ return 1; -+} -+ -+/* -+ * ip7500media_video_init -+ * Called late to determine what kind of video we have on this board -+ */ -+static int __init ip7500media_video_init(void) -+{ -+ struct i2c_adapter *adap; -+ struct i2c_msg msg[1]; -+ unsigned char *data; -+ unsigned char checksum; -+ int err; -+ int i; -+ -+ if (vdc_override == 1) { -+ printk(KERN_INFO "Force VDCTIO mode\n"); -+ goto no_adapter; -+ } -+ if (vdc_override == 2) { -+ printk(KERN_INFO "Force LCD Adapter Board mode\n"); -+ return 0; -+ } -+ -+ /* -+ * Check to see if there is an EEPROM out there. If we see an -+ * EEPROM then we will assume a LCD Adapter Board (8007-092x) -+ * exists. -+ */ -+ data = kmalloc(256, GFP_KERNEL); -+ if (!data) { -+ printk(KERN_WARNING "%s: Failed to allocate memory\n", __FUNCTION__); -+ return -ENOMEM; -+ } -+ -+ adap = i2c_get_adapter(0); -+ if (!adap) { -+ printk(KERN_WARNING "%s: Failed to get i2c adapter\n", __FUNCTION__); -+ kfree(data); -+ return -ENODEV; -+ } -+ data[0] = 0; -+ msg->addr = 0x50; -+ msg->flags = 0; -+ msg->len = 1; -+ msg->buf = data; -+ err = i2c_transfer(adap, msg, 1); -+ if (err < 0) { -+ goto no_adapter; -+ } -+ -+ msg->addr = 0x50; -+ msg->flags = I2C_M_RD; -+ msg->len = 256; -+ msg->buf = data; -+ err = i2c_transfer(adap, msg, 1); -+ if (err < 0) { -+ goto no_adapter; -+ } -+ -+ i2c_put_adapter(adap); -+ -+ /* -+ * Verify the checksum -+ */ -+ checksum = 0xff; -+ for (i = 0; i < 255; i++) { -+ checksum ^= data[i]; -+ } -+ if (checksum != data[255]) { -+ printk(KERN_WARNING "%s: Checksum mismatch\n", __FUNCTION__); -+ } -+ -+ kfree(data); -+ -+ /* -+ * Bring up VFB -+ */ -+ platform_device_register(&ip7500media_vfb_device); -+ -+ /* -+ * Add the i2c devices on the LCD Adapter board. (We have to use i2c_new_device -+ * since it's late in the boot process.) -+ */ -+ printk(KERN_INFO "%s: registering LCD Adapter board i2c resources\n", __FUNCTION__); -+ for (i = 0; i < ARRAY_SIZE(ip7500media_lcd_adapter_i2c_board_info); i++) { -+ i2c_new_device(adap, &ip7500media_lcd_adapter_i2c_board_info[i]); -+ } -+ -+ i2c_put_adapter(adap); -+ -+ return 0; -+ -+ /* -+ * No LCD Adapter board, bring up VDC -+ */ -+no_adapter: -+ vdc_tio_init(); -+ return 0; -+} -+late_initcall(ip7500media_video_init); -+__setup("forcevdc=", ip7500media_set_forcevdc); -+ -+/* -+ * ip7500media_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip7500media_init(void) -+{ -+ struct platform_device *audio_dev; -+ int have_ethernet = (devtree_find_node("eth_lan") != 0); -+ -+ board_init(); -+ -+ ubi_gpio_init(); -+ -+#ifdef CONFIG_UIO_UBICOM32RING -+ ring_tio_init("decoder_ring"); -+#endif -+ -+ /* -+ * Register all of the devices we have on this board -+ */ -+ printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__); -+ platform_device_register(&ip7500media_i2c_device); -+ platform_device_register(&ip7500media_backlight_device); -+ -+ /* -+ * If ethernet doesn't exist then we can init the lcdpower -+ */ -+ if (!have_ethernet) { -+ platform_device_register(&ip7500media_lcdpower_device); -+ } -+ -+ /* -+ * Allocate the audio drivers. SPDIF not supported on boards with ethernet. -+ */ -+ audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0); -+ if (audio_dev) { -+ ip7500media_i2c_board_info[0].platform_data = audio_dev; -+ } -+ -+ if (!have_ethernet) { -+ struct platform_device *audio_dev2; -+ -+ audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0); -+ if (audio_dev2) { -+ platform_device_register(audio_dev2); -+ } -+ } -+ -+ /* -+ * Register all of the devices which sit on the I2C bus -+ */ -+ printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); -+ i2c_register_board_info(0, ip7500media_i2c_board_info, ARRAY_SIZE(ip7500media_i2c_board_info)); -+ -+ /* -+ * We have to initialize the SDIO after the I2C IOB gets setup. SDIO is initialized in -+ * ip7500media_u17_setup -+ */ -+ -+ printk("IP7500 Media Board\n"); -+ -+ return 0; -+} -+ -+arch_initcall(ip7500media_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500module.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500module.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500module.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500module.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,55 @@ -+/* -+ * arch/ubicom32/mach-ip7k/board-ip7500module.c -+ * Support for IP7500 CPU module board. -+ * -+ * This file supports the IP7500 CPU module board: -+ * 8007-0510 Rev 1.0 -+ * 8007-0510A Rev 1.0 (with ethernet) -+ * -+ * DIP Switch SW2 configuration: (*) default -+ * POS 1: on(*) = PCI enabled, off = PCI disabled -+ * POS 2: on(*) = TTYX => PA6, off = TTYX => PF12 -+ * POS 3: on(*) = TTYY => PA7, off = TTYY => PF15 -+ * POS 4: unused -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+ -+/* -+ * ip7500module_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip7500module_init(void) -+{ -+ board_init(); -+ -+ ubi_gpio_init(); -+ -+ return 0; -+} -+ -+arch_initcall(ip7500module_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,101 @@ -+/* -+ * arch/ubicom32/mach-ip7k/board-ip7500wspkr.c -+ * Support for IP7500 Wireless Speaker board. -+ * -+ * This file supports the IP7500 Wireless Speaker board: -+ * 8007-1210 Rev 1.0 -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+static struct i2c_board_info __initdata ip7500wspkr_i2c_board_info[] = { -+ /* -+ * U6, CS4350 DAC, address 0x4B -+ */ -+ { -+ .type = "cs4350", -+ .addr = 0x4B, -+ }, -+}; -+ -+/* -+ * I2C bus on the board, SDA PE4, SCL PE5 -+ */ -+static struct i2c_gpio_platform_data ip7500wspkr_i2c_data = { -+ .sda_pin = GPIO_RD_5, -+ .scl_pin = GPIO_RD_6, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+ .udelay = 50, -+}; -+ -+static struct platform_device ip7500wspkr_i2c_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { -+ .platform_data = &ip7500wspkr_i2c_data, -+ }, -+}; -+ -+static struct platform_device *ip7500wspkr_devices[] __initdata = { -+ &ip7500wspkr_i2c_device, -+}; -+ -+/* -+ * ip7500wspkr_init -+ * Called to add the devices which we have on this board -+ */ -+static int __init ip7500wspkr_init(void) -+{ -+ struct platform_device *audio_dev; -+ struct platform_device *audio_dev2; -+ -+ board_init(); -+ -+ ubi_gpio_init(); -+ -+ platform_add_devices(ip7500wspkr_devices, ARRAY_SIZE(ip7500wspkr_devices)); -+ -+ audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0); -+ if (audio_dev) { -+ ip7500wspkr_i2c_board_info[0].platform_data = audio_dev; -+ } -+ -+ audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0); -+ if (audio_dev2) { -+ platform_device_register(audio_dev2); -+ } -+ -+ printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__); -+ i2c_register_board_info(0, ip7500wspkr_i2c_board_info, ARRAY_SIZE(ip7500wspkr_i2c_board_info)); -+ -+ printk(KERN_INFO "IP7500 Wireless Speaker Board\n"); -+ -+ return 0; -+} -+ -+arch_initcall(ip7500wspkr_init); -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/Kconfig linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/Kconfig ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/Kconfig 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/Kconfig 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,205 @@ -+config IP7145DPF -+ bool "IP7145DPF" -+ select UBICOM32_V4 -+ select UBICOM_INPUT -+ select UBICOM_INPUT_I2C -+ select RTC_CLASS -+ select RTC_DRV_S35390A -+ select I2C -+ select I2C_GPIO -+ select GPIO_PCA953X -+ select FB -+ select FB_UBICOM32 -+ select LCD_CLASS_DEVICE -+ select LCD_UBICOM32POWER -+ select BACKLIGHT_LCD_SUPPORT -+ select BACKLIGHT_CLASS_DEVICE -+ select BACKLIGHT_UBICOM32 -+ select SND_UBI32 -+ select MMC_UBICOM32 -+ select MMC -+ select MMC_BLOCK -+ help -+ IP7145 Digital Picture Frame reference design, supports: -+ 8007-0410 v1.0 -+ -+config IP7160RGW -+ bool "IP7160RGW" -+ select UBICOM32_V4 -+ select UBICOM_INPUT -+ select NEW_LEDS -+ select LEDS_CLASS -+ select LEDS_GPIO -+ select SPI -+ select SPI_UBICOM32_GPIO -+ select VLAN_8021Q -+ select UBICOM_SWITCH -+ select UBICOM_SWITCH_BCM539X -+ help -+ Ubicom IP7160 RGW Eval, supports: -+ 8007-0110 v1.0 -+ 8007-0111 v1.1 -+ 8007-0112 v1.2 -+ -+config IP7160RGWLCD -+ bool "IP7160RGWLCD" -+ select UBICOM32_V4 -+ select UBICOM_INPUT -+ select NEW_LEDS -+ select LEDS_CLASS -+ select LEDS_GPIO -+ select SPI -+ select SPI_UBICOM32_GPIO -+ select VLAN_8021Q -+ select UBICOM_SWITCH -+ select UBICOM_SWITCH_BCM539X -+ select INPUT_TOUCHSCREEN -+ select TOUCHSCREEN_TSC2007 -+ select FB -+ select FB_UBICOM32_VIRTUAL -+ select I2C -+ select I2C_GPIO -+ help -+ Ubicom IP7160 RGW Eval, supports: -+ 8007-0112 v1.2 + 8007-1410 v1.0 -+ -+ With Ubicom LCD Adapter -+ 8007-0920 v2.0 -+ 8007-0921 v2.1 -+ -+ -+config IP7160BRINGUP -+ bool "IP7160BRINGUP" -+ select UBICOM32_V4 -+ select NEW_LEDS -+ select LEDS_CLASS -+ select LEDS_GPIO -+ help -+ Ubicom IP7160 Bringup, supports: -+ 8007-0010 v1.0 -+ -+config IP7160DPF -+ bool "IP7160DPF" -+ select UBICOM32_V4 -+ select I2C -+ select I2C_GPIO -+ select FB -+ select FB_UBICOM32 -+ select BACKLIGHT_LCD_SUPPORT -+ select BACKLIGHT_CLASS_DEVICE -+ select SND_UBI32 -+ select SND_UBI32_AUDIO_CS4350 -+ select UBICOM_HID -+ help -+ IP7160 Digital Picture Frame board, supports: -+ 8007-0211 Rev 1.1 -+ -+config IP7500MODULE -+ bool "IP7500MODULE" -+ select UBICOM32_V4 -+ help -+ Ubicom IP7500 CPU Module board, supports: -+ 8007-0510 v1.0 -+ 8007-0510A v1.0 -+ -+ Please see ip7500module.c for more details. -+ -+config IP7500AV -+ bool "IP7500AV" -+ select UBICOM32_V4 -+ select I2C -+ select I2C_GPIO -+ select SND_UBI32 -+ select SND_UBI32_AUDIO_CS4384 -+ select FB -+ select FB_UBICOM32 -+ help -+ Ubicom IP7500 Audio Video board, supports: -+ 8007-0810 v1.0 -+ -+ With Ubicom IP7500 CPU Module board: -+ 8007-0510 v1.0 -or- -+ 8007-0510A v1.0 -+ -+ Please see ip7500av.c for more details. -+ -+config IP7500MEDIA -+ bool "IP7500MEDIA" -+ select UBICOM32_V4 -+ select UBICOM_INPUT_I2C -+ select RTC_CLASS -+ select RTC_DRV_S35390A -+ select I2C -+ select I2C_GPIO -+ select GPIO_PCA953X -+ select FB -+ select FB_UBICOM32 -+ select FB_UBICOM32_VIRTUAL -+ select FB_UBICOM32_VIRTUAL_NOAUTO -+ select LCD_CLASS_DEVICE -+ select LCD_UBICOM32POWER -+ select BACKLIGHT_LCD_SUPPORT -+ select BACKLIGHT_CLASS_DEVICE -+ select BACKLIGHT_UBICOM32 -+ select INPUT_TOUCHSCREEN -+ select TOUCHSCREEN_TSC2007 -+ select SOUND -+ select SND -+ select SND_UBI32 -+ select SND_UBI32_AUDIO_CS4350 -+ select MMC_UBICOM32 -+ select MMC -+ select MMC_BLOCK -+ help -+ IP7500 Media Board w/ IP7500 CPU Module board, supports: -+ 8007-0610 v1.0 w/ 8007-0510 v1.0 -+ 8007-0610 v1.0 w/ 8007-0510 v1.0 NOPHY -+ 8007-0610 v1.0 w/ 8007-0511 v1.1 NOPHY -+ -+ Also supports optional LCD Adapter board: -+ 8006-0920 v2.0 -+ 8006-0921 v2.1 -+ -+ Please see ip7500media.c for more details. -+ -+config IP7500WSPKR -+ bool "IP7500WSPKR" -+ select UBICOM32_V4 -+ select I2C -+ select I2C_GPIO -+ select SOUND -+ select SND -+ select SND_UBI32 -+ select SND_UBI32_AUDIO_CS4350 -+ help -+ IP7500 Wireless Speaker Board, supports: -+ 8007-1210 v1.0 -+ -+ Please see ip7500wspkr.c for more details. -+ -+config IP7500IAP -+ bool "IP7500IAP" -+ select UBICOM32_V4 -+ select I2C -+ select I2C_GPIO -+ select FB -+ select FB_UBICOM32_VIRTUAL -+ select SOUND -+ select SND -+ select SND_UBI32 -+ select SND_UBI32_AUDIO_CS4350 -+ select RTC_CLASS -+ select RTC_DRV_S35390A -+ select INPUT_TOUCHSCREEN -+ select TOUCHSCREEN_TSC2007 -+ select BACKLIGHT_LCD_SUPPORT -+ select BACKLIGHT_CLASS_DEVICE -+ select BACKLIGHT_UBICOM32 -+ help -+ IP7500 Internet Audio Player, supports: -+ 8007-1110 v1.0 -+ -+ Please see ip7500iap.c for more details. -+ -+ -+ Please see ip7500media.c for more details. -diff -ruN linux-2.6.30.10/arch/ubicom32/mach-ip7k/Makefile linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/Makefile ---- linux-2.6.30.10/arch/ubicom32/mach-ip7k/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mach-ip7k/Makefile 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,38 @@ -+# -+# arch/ubicom32/mach-ip7k/Makefile -+# Makefile for ip7k based boards. -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+ -+obj-$(CONFIG_IP7145DPF) += board-ip7145dpf.o -+obj-$(CONFIG_IP7160RGW) += board-ip7160rgw.o -+obj-$(CONFIG_IP7160RGWLCD) += board-ip7160rgw.o -+obj-$(CONFIG_IP7160BRINGUP) += board-ip7160bringup.o -+obj-$(CONFIG_IP7160DPF) += board-ip7160dpf.o -+obj-$(CONFIG_IP7500MODULE) += board-ip7500module.o -+obj-$(CONFIG_IP7500MEDIA) += board-ip7500media.o -+obj-$(CONFIG_IP7500AV) += board-ip7500av.o -+obj-$(CONFIG_IP7500WSPKR) += board-ip7500wspkr.o -+obj-$(CONFIG_IP7500IAP) += board-ip7500iap.o -diff -ruN linux-2.6.30.10/arch/ubicom32/Makefile linux-2.6.30.10-ubi/arch/ubicom32/Makefile ---- linux-2.6.30.10/arch/ubicom32/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/Makefile 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,104 @@ -+# -+# arch/ubicom32/Makefile -+# -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+ -+KBUILD_DEFCONFIG := -+ -+# setup the machine name and machine dependent settings -+machine-$(CONFIG_UBICOM32_V3) := ip5k -+machine-$(CONFIG_UBICOM32_V4) := ip7k -+MACHINE := $(machine-y) -+export MACHINE -+ -+model-$(CONFIG_RAMKERNEL) := ram -+model-$(CONFIG_ROMKERNEL) := rom -+MODEL := $(model-y) -+export MODEL -+ -+CPUCLASS := $(cpuclass-y) -+ -+export CPUCLASS -+ -+# -+# We want the core kernel built using the fastcall ABI but modules need -+# to be built using the slower calling convention because they could be -+# loaded out of range for fast calls. -+# -+CFLAGS_KERNEL += -mfastcall -+CFLAGS_MODULE += -mno-fastcall -+ -+# -+# Some CFLAG additions based on specific CPU type. -+# -+cflags-$(CONFIG_UBICOM32_V3) := -march=ubicom32v3 -DIP5000 -+cflags-$(CONFIG_UBICOM32_V4) := -march=ubicom32v4 -DIP7000 -+ -+ldflags-$(CONFIG_LINKER_RELAXATION) := --relax -+LDFLAGS_vmlinux := $(ldflags-y) -+ -+GCCLIBDIR := $(dir $(shell $(CC) $(cflags-y) -print-libgcc-file-name)) -+GCC_LIBS := $(GCCLIBDIR)/libgcc.a -+ -+KBUILD_CFLAGS += $(cflags-y) -ffunction-sections -+KBUILD_AFLAGS += $(cflags-y) -+ -+KBUILD_CFLAGS += -D__linux__ -Dlinux -+KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\" -+ -+# include any machine specific directory -+ifneq ($(machine-y),) -+core-y += arch/$(ARCH)/mach-$(MACHINE)/ -+endif -+ -+head-y := arch/$(ARCH)/kernel/head.o -+ -+core-y += arch/$(ARCH)/kernel/ \ -+ arch/$(ARCH)/mm/ \ -+ arch/$(ARCH)/crypto/ \ -+ arch/$(ARCH)/mach-common/ -+ -+drivers-$(CONFIG_OPROFILE) += arch/ubicom32/oprofile/ -+ -+libs-y += arch/$(ARCH)/lib/ -+libs-y += $(GCC_LIBS) -+ -+archclean: -+ -+# make sure developer has selected a valid board -+ifeq ($(CONFIG_NOBOARD),y) -+# $(error have to select a valid board file $(CONFIG_NOBOARD), please run kernel config again) -+_all: config_board_error -+endif -+ -+config_board_error: -+ @echo "*************************************************" -+ @echo "You have not selected a proper board." -+ @echo "Please run menuconfig (or config) against your" -+ @echo "kernel and choose your board under Processor" -+ @echo "options" -+ @echo "*************************************************" -+ @exit 1 -diff -ruN linux-2.6.30.10/arch/ubicom32/mm/fault.c linux-2.6.30.10-ubi/arch/ubicom32/mm/fault.c ---- linux-2.6.30.10/arch/ubicom32/mm/fault.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mm/fault.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,80 @@ -+/* -+ * arch/ubicom32/mm/fault.c -+ * Ubicom32 architecture page fault implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1998 D. Jeff Dionne , -+ * Copyright (C) 2000 Lineo, Inc. (www.lineo.com) -+ * -+ * Based on: -+ * -+ * linux/arch/m68k/mm/fault.c -+ * -+ * Copyright (C) 1995 Hamish Macdonald -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+extern void die_if_kernel(char *, struct pt_regs *, long); -+ -+/* -+ * This routine handles page faults. It determines the problem, and -+ * then passes it off to one of the appropriate routines. -+ * -+ * error_code: -+ * bit 0 == 0 means no page found, 1 means protection fault -+ * bit 1 == 0 means read, 1 means write -+ * -+ * If this routine detects a bad access, it returns 1, otherwise it -+ * returns 0. -+ */ -+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, -+ unsigned long error_code) -+{ -+#ifdef DEBUG -+ printk (KERN_DEBUG "regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n", -+ regs->sr, regs->pc, address, error_code); -+#endif -+ -+ /* -+ * Oops. The kernel tried to access some bad page. We'll have to -+ * terminate things with extreme prejudice. -+ */ -+ if ((unsigned long) address < PAGE_SIZE) { -+ printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); -+ } else -+ printk(KERN_ALERT "Unable to handle kernel access"); -+ printk(KERN_ALERT " at virtual address %08lx\n",address); -+ die_if_kernel("Oops", regs, error_code); -+ do_exit(SIGKILL); -+ -+ return 1; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mm/init.c linux-2.6.30.10-ubi/arch/ubicom32/mm/init.c ---- linux-2.6.30.10/arch/ubicom32/mm/init.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mm/init.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,262 @@ -+/* -+ * arch/ubicom32/mm/init.c -+ * Ubicom32 architecture virtual memory initialization. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1998 D. Jeff Dionne , -+ * Kenneth Albanowski , -+ * Copyright (C) 2000 Lineo, Inc. (www.lineo.com) -+ * -+ * Based on: -+ * -+ * linux/arch/m68k/mm/init.c -+ * -+ * Copyright (C) 1995 Hamish Macdonald -+ * -+ * JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com) -+ * DEC/2000 -- linux 2.4 support -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#undef DEBUG -+ -+extern void die_if_kernel(char *,struct pt_regs *,long); -+extern void free_initmem(void); -+ -+/* -+ * BAD_PAGE is the page that is used for page faults when linux -+ * is out-of-memory. Older versions of linux just did a -+ * do_exit(), but using this instead means there is less risk -+ * for a process dying in kernel mode, possibly leaving a inode -+ * unused etc.. -+ * -+ * BAD_PAGETABLE is the accompanying page-table: it is initialized -+ * to point to BAD_PAGE entries. -+ * -+ * ZERO_PAGE is a special page that is used for zero-initialized -+ * data and COW. -+ */ -+static unsigned long empty_bad_page_table; -+ -+static unsigned long empty_bad_page; -+ -+unsigned long empty_zero_page; -+ -+void show_mem(void) -+{ -+ unsigned long i; -+ int free = 0, total = 0, reserved = 0, shared = 0; -+ int cached = 0; -+ -+ printk(KERN_INFO "\nMem-info:\n"); -+ show_free_areas(); -+ i = max_mapnr; -+ while (i-- > 0) { -+ total++; -+ if (PageReserved(mem_map+i)) -+ reserved++; -+ else if (PageSwapCache(mem_map+i)) -+ cached++; -+ else if (!page_count(mem_map+i)) -+ free++; -+ else -+ shared += page_count(mem_map+i) - 1; -+ } -+ printk(KERN_INFO "%d pages of RAM\n",total); -+ printk(KERN_INFO "%d free pages\n",free); -+ printk(KERN_INFO "%d reserved pages\n",reserved); -+ printk(KERN_INFO "%d pages shared\n",shared); -+ printk(KERN_INFO "%d pages swap cached\n",cached); -+} -+ -+extern unsigned long memory_start; -+extern unsigned long memory_end; -+extern char __ocm_free_begin; -+extern char __ocm_free_end; -+ -+/* -+ * paging_init() continues the virtual memory environment setup which -+ * was begun by the code in arch/head.S. -+ * The parameters are pointers to where to stick the starting and ending -+ * addresses of available kernel virtual memory. -+ */ -+void __init paging_init(void) -+{ -+ /* -+ * Make sure start_mem is page aligned, otherwise bootmem and -+ * page_alloc get different views of the world. -+ */ -+#ifdef DEBUG -+ unsigned long start_mem = PAGE_ALIGN(memory_start); -+#endif -+ unsigned long end_mem = memory_end & PAGE_MASK; -+ -+#ifdef DEBUG -+ printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n", -+ start_mem, end_mem); -+#endif -+ -+ /* -+ * Initialize the bad page table and bad page to point -+ * to a couple of allocated pages. -+ */ -+ empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); -+ empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); -+ empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); -+ memset((void *)empty_zero_page, 0, PAGE_SIZE); -+ -+ /* -+ * TODO: enable setting up for user memory management interface. -+ */ -+ -+#ifdef DEBUG -+ printk (KERN_DEBUG "before free_area_init\n"); -+ -+ printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n", -+ start_mem, end_mem); -+#endif -+ -+ { -+ unsigned long zones_size[MAX_NR_ZONES] = {0, }; -+#ifdef CONFIG_ZONE_DMA -+ zones_size[ZONE_DMA] = OCMSIZE >> PAGE_SHIFT; -+#endif -+ zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT; -+#ifdef CONFIG_HIGHMEM -+ zones_size[ZONE_HIGHMEM] = 0; -+#endif -+ free_area_init(zones_size); -+ } -+} -+ -+void __init mem_init(void) -+{ -+ int codek = 0, datak = 0, initk = 0; -+ unsigned long tmp, ram_start, ram_end, len; -+ extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end; -+ -+ unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */ -+ unsigned long end_mem = memory_end; /* DAVIDM - this must not include kernel stack at top */ -+ processor_dram(&ram_start, &ram_end); -+ len = (ram_end - ram_start) + OCMSIZE; -+#ifdef DEBUG -+ printk(KERN_DEBUG "Mem_init: start=%lx, end=%lx\n", start_mem, end_mem); -+#endif -+ -+ end_mem &= PAGE_MASK; -+ high_memory = (void *) end_mem; -+ -+ start_mem = PAGE_ALIGN(start_mem); -+ max_mapnr = num_physpages = (((unsigned long) high_memory) - PAGE_OFFSET) >> PAGE_SHIFT; -+ -+ /* this will put all memory onto the freelists */ -+#ifdef CONFIG_ZONE_DMA -+ { -+ unsigned long ocm_free_begin = (unsigned long)&__ocm_free_begin; -+ unsigned long ocm_free_end = (unsigned long)&__ocm_free_end; -+ unsigned long zone_dma_begin = (ocm_free_begin + PAGE_SIZE - 1) & PAGE_MASK; -+ unsigned long zone_dma_end = ocm_free_end & PAGE_MASK; -+ if (zone_dma_end > zone_dma_begin) -+ free_bootmem(zone_dma_begin, zone_dma_end-zone_dma_begin); -+ } -+#endif -+ totalram_pages = free_all_bootmem(); -+ -+ codek = (&_etext - &_stext) >> 10; -+ datak = (&_ebss - &_sdata) >> 10; -+ initk = (&__init_begin - &__init_end) >> 10; -+ -+ tmp = nr_free_pages() << PAGE_SHIFT; -+ printk(KERN_INFO "Memory available: %luk/%luk RAM, (%dk kernel code, %dk data)\n", -+ tmp >> 10, -+ len >> 10, -+ codek, -+ datak -+ ); -+ -+} -+ -+#ifdef CONFIG_BLK_DEV_INITRD -+void free_initrd_mem(unsigned long start, unsigned long end) -+{ -+ int pages = 0; -+ for (; start < end; start += PAGE_SIZE) { -+ ClearPageReserved(virt_to_page(start)); -+ init_page_count(virt_to_page(start)); -+ free_page(start); -+ totalram_pages++; -+ pages++; -+ } -+ printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages); -+} -+#endif -+ -+void -+free_initmem() -+{ -+#ifdef CONFIG_RAMKERNEL -+ unsigned long addr; -+ extern char __init_begin, __init_end; -+ /* -+ * The following code should be cool even if these sections -+ * are not page aligned. -+ */ -+ addr = PAGE_ALIGN((unsigned long)(&__init_begin)); -+ /* next to check that the page we free is not a partial page */ -+ for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) { -+ ClearPageReserved(virt_to_page(addr)); -+ init_page_count(virt_to_page(addr)); -+ free_page(addr); -+ totalram_pages++; -+ } -+ printk(KERN_NOTICE "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n", -+ (addr - PAGE_ALIGN((long) &__init_begin)) >> 10, -+ (int)(PAGE_ALIGN((unsigned long)(&__init_begin))), -+ (int)(addr - PAGE_SIZE)); -+#endif -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mm/kmap.c linux-2.6.30.10-ubi/arch/ubicom32/mm/kmap.c ---- linux-2.6.30.10/arch/ubicom32/mm/kmap.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mm/kmap.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,79 @@ -+/* -+ * arch/ubicom32/mm/kmap.c -+ * Ubicom32 architecture non-mmu ioremap and friends implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2000 Lineo, -+ * Copyright (C) 2000-2002 David McCullough -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#undef DEBUG -+ -+/* -+ * Map some physical address range into the kernel address space. -+ */ -+void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) -+{ -+ return (void *)physaddr; -+} -+ -+/* -+ * Unmap a ioremap()ed region again. -+ */ -+void iounmap(void *addr) -+{ -+} -+ -+/* -+ * __iounmap unmaps nearly everything, so be careful -+ * it doesn't free currently pointer/page tables anymore but it -+ * wans't used anyway and might be added later. -+ */ -+void __iounmap(void *addr, unsigned long size) -+{ -+} -+ -+/* -+ * Set new cache mode for some kernel address space. -+ * The caller must push data for that range itself, if such data may already -+ * be in the cache. -+ */ -+void kernel_set_cachemode(void *addr, unsigned long size, int cmode) -+{ -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mm/Makefile linux-2.6.30.10-ubi/arch/ubicom32/mm/Makefile ---- linux-2.6.30.10/arch/ubicom32/mm/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mm/Makefile 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,32 @@ -+# -+# arch/ubicom32/mm/Makefile -+# -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+# -+# Makefile for the linux m68knommu specific parts of the memory manager. -+# -+ -+obj-y += init.o fault.o memory.o kmap.o ocm-alloc.o -diff -ruN linux-2.6.30.10/arch/ubicom32/mm/memory.c linux-2.6.30.10-ubi/arch/ubicom32/mm/memory.c ---- linux-2.6.30.10/arch/ubicom32/mm/memory.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mm/memory.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,58 @@ -+/* -+ * arch/ubicom32/mm/memory.c -+ * Ubicom32 architecture kernel_map() implementation. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 1998 Kenneth Albanowski , -+ * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) -+ * -+ * Based on: -+ * -+ * linux/arch/m68k/mm/memory.c -+ * -+ * Copyright (C) 1995 Hamish Macdonald -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * Map some physical address range into the kernel address space. -+ * The code is copied and adapted from map_chunk(). -+ */ -+ -+unsigned long kernel_map(unsigned long paddr, unsigned long size, -+ int nocacheflag, unsigned long *memavailp ) -+{ -+ return paddr; -+} -diff -ruN linux-2.6.30.10/arch/ubicom32/mm/ocm-alloc.c linux-2.6.30.10-ubi/arch/ubicom32/mm/ocm-alloc.c ---- linux-2.6.30.10/arch/ubicom32/mm/ocm-alloc.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/mm/ocm-alloc.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,487 @@ -+/* -+ * arch/ubicom32/mm/ocm-alloc.c -+ * OCM allocator for Uibcom32 On-Chip memory -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright 2004-2008 Analog Devices Inc. -+ * -+ * Based on: -+ * -+ * arch/blackfin/mm/sram-alloc.c -+ * -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if 0 -+#define DEBUGP printk -+#else -+#define DEBUGP(fmt, a...) -+#endif -+/* -+ * the data structure for OCM heap pieces -+ */ -+struct ocm_piece { -+ void *paddr; -+ int size; -+ pid_t pid; -+ struct ocm_piece *next; -+}; -+ -+/* -+ * struct ocm_heap -+ */ -+struct ocm_heap { -+ struct ocm_piece free_head; -+ struct ocm_piece used_head; -+ struct mutex lock; -+}; -+ -+static struct ocm_heap ocm_inst_heap; -+int ubi32_ocm_skbuf_max = 21, ubi32_ocm_skbuf, ubi32_ddr_skbuf; -+ -+/* -+ * OCM area for storing code -+ */ -+extern asmlinkage void *__ocm_free_begin; -+extern asmlinkage void *__ocm_free_end; -+extern asmlinkage void *__ocm_inst_heap_begin; -+extern asmlinkage void *__ocm_inst_heap_end; -+#define OCM_INST_HEAP_BEGIN ((unsigned int)&__ocm_inst_heap_begin) -+#define OCM_INST_HEAP_END ((unsigned int)&__ocm_inst_heap_end) -+#define OCM_INST_HEAP_LENGTH (OCM_INST_HEAP_END - OCM_INST_HEAP_BEGIN) -+ -+static struct kmem_cache *ocm_piece_cache; -+ -+/* -+ * _ocm_heap_init() -+ */ -+static int __init _ocm_heap_init(struct ocm_heap *ocmh, -+ unsigned int start, -+ unsigned int size) -+{ -+ ocmh->free_head.next = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL); -+ -+ if (!ocmh->free_head.next) -+ return -1; -+ -+ ocmh->free_head.next->paddr = (void *)start; -+ ocmh->free_head.next->size = size; -+ ocmh->free_head.next->pid = 0; -+ ocmh->free_head.next->next = 0; -+ -+ ocmh->used_head.next = NULL; -+ -+ /* mutex initialize */ -+ mutex_init(&ocmh->lock); -+ -+ return 0; -+} -+ -+/* -+ * _ocm_alloc_init() -+ * -+ * starts the ocm heap(s) -+ */ -+static int __init _ocm_alloc_init(void) -+{ -+ if (OCM_INST_HEAP_LENGTH) { -+ ocm_piece_cache = kmem_cache_create("ocm_piece_cache", -+ sizeof(struct ocm_piece), -+ 0, SLAB_PANIC, NULL); -+ -+ if (_ocm_heap_init(&ocm_inst_heap, -+ OCM_INST_HEAP_BEGIN, -+ OCM_INST_HEAP_LENGTH) == 0) -+ printk(KERN_INFO "OCM Instruction Heap %d KB\n", -+ OCM_INST_HEAP_LENGTH >> 10); -+ else -+ printk(KERN_INFO "Failed to initialize OCM " -+ "Instruction Heap\n"); -+ -+ } else -+ printk(KERN_INFO "No space available for OCM " -+ "Instruction Heap\n"); -+ -+ return 0; -+} -+pure_initcall(_ocm_alloc_init); -+ -+/* -+ * _ocm_alloc() -+ * generic alloc a block in the ocm heap, if successful -+ * returns the pointer. -+ */ -+static void *_ocm_alloc(size_t size, pid_t pid, struct ocm_heap *ocmheap) -+{ -+ struct ocm_piece *pslot, *plast, *pavail; -+ struct ocm_piece *pfree_head = &ocmheap->free_head; -+ struct ocm_piece *pused_head = &ocmheap->used_head; -+ -+ if (size <= 0 || !pfree_head || !pused_head) -+ return NULL; -+ -+ /* Align the size */ -+ size = (size + 3) & ~3; -+ -+ pslot = pfree_head->next; -+ plast = pfree_head; -+ -+ /* -+ * search an available piece slot -+ */ -+ while (pslot != NULL && size > pslot->size) { -+ plast = pslot; -+ pslot = pslot->next; -+ } -+ -+ if (!pslot) -+ return NULL; -+ -+ if (pslot->size == size) { -+ /* -+ * Unlink this block from the list -+ */ -+ plast->next = pslot->next; -+ pavail = pslot; -+ } else { -+ /* -+ * Split this block in two. -+ */ -+ pavail = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL); -+ -+ if (!pavail) -+ return NULL; -+ -+ pavail->paddr = pslot->paddr; -+ pavail->size = size; -+ pslot->paddr += size; -+ pslot->size -= size; -+ } -+ -+ pavail->pid = pid; -+ -+ pslot = pused_head->next; -+ plast = pused_head; -+ -+ /* -+ * insert new piece into used piece list !!! -+ */ -+ while (pslot != NULL && pavail->paddr < pslot->paddr) { -+ plast = pslot; -+ pslot = pslot->next; -+ } -+ -+ pavail->next = pslot; -+ plast->next = pavail; -+ -+ DEBUGP("_ocm_alloc %d bytes at %p from in %p", -+ size, pavail->paddr, ocmheap); -+ -+ return pavail->paddr; -+} -+ -+#if 0 -+/* Allocate the largest available block. */ -+static void *_ocm_alloc_max(struct ocm_heap *ocmheap, -+ unsigned long *psize) -+{ -+ struct ocm_piece *pfree_head = &ocmheap->free_head; -+ struct ocm_piece *pslot, *pmax; -+ -+ pmax = pslot = pfree_head->next; -+ -+ /* search an available piece slot */ -+ while (pslot != NULL) { -+ if (pslot->size > pmax->size) -+ pmax = pslot; -+ pslot = pslot->next; -+ } -+ -+ if (!pmax) -+ return NULL; -+ -+ *psize = pmax->size; -+ -+ return _ocm_alloc(*psize, ocmheap); -+} -+#endif -+ -+/* -+ * _ocm_free() -+ * generic free a block in the ocm heap, if successful -+ */ -+static int _ocm_free(const void *addr, -+ struct ocm_heap *ocmheap) -+{ -+ struct ocm_piece *pslot, *plast, *pavail; -+ struct ocm_piece *pfree_head = &ocmheap->free_head; -+ struct ocm_piece *pused_head = &ocmheap->used_head; -+ -+ /* search the relevant memory slot */ -+ pslot = pused_head->next; -+ plast = pused_head; -+ -+ /* search an available piece slot */ -+ while (pslot != NULL && pslot->paddr != addr) { -+ plast = pslot; -+ pslot = pslot->next; -+ } -+ -+ if (!pslot) { -+ DEBUGP("_ocm_free %p not found in %p", addr, ocmheap); -+ return -1; -+ } -+ DEBUGP("_ocm_free %p from in %p", addr, ocmheap); -+ -+ plast->next = pslot->next; -+ pavail = pslot; -+ pavail->pid = 0; -+ -+ /* insert free pieces back to the free list */ -+ pslot = pfree_head->next; -+ plast = pfree_head; -+ -+ while (pslot != NULL && addr > pslot->paddr) { -+ plast = pslot; -+ pslot = pslot->next; -+ } -+ -+ if (plast != pfree_head && -+ plast->paddr + plast->size == pavail->paddr) { -+ plast->size += pavail->size; -+ kmem_cache_free(ocm_piece_cache, pavail); -+ } else { -+ pavail->next = plast->next; -+ plast->next = pavail; -+ plast = pavail; -+ } -+ -+ if (pslot && plast->paddr + plast->size == pslot->paddr) { -+ plast->size += pslot->size; -+ plast->next = pslot->next; -+ kmem_cache_free(ocm_piece_cache, pslot); -+ } -+ -+ return 0; -+} -+ -+/* -+ * ocm_inst_alloc() -+ * -+ * allocates a block of size in the ocm instrction heap, if -+ * successful returns address allocated. -+ */ -+void *ocm_inst_alloc(size_t size, pid_t pid) -+{ -+ void *addr; -+ -+ if (!OCM_INST_HEAP_LENGTH) -+ return NULL; -+ -+ -+ mutex_lock(&ocm_inst_heap.lock); -+ -+ addr = _ocm_alloc(size, pid, &ocm_inst_heap); -+ -+ mutex_unlock(&ocm_inst_heap.lock); -+ -+ return addr; -+} -+EXPORT_SYMBOL(ocm_inst_alloc); -+ -+/* -+ * ocm_inst_free() -+ * free a block in the ocm instrction heap, returns 0 if successful. -+ */ -+int ocm_inst_free(const void *addr) -+{ -+ int ret; -+ -+ if (!OCM_INST_HEAP_LENGTH) -+ return -1; -+ -+ mutex_lock(&ocm_inst_heap.lock); -+ -+ ret = _ocm_free(addr, &ocm_inst_heap); -+ -+ mutex_unlock(&ocm_inst_heap.lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(ocm_inst_free); -+ -+/* -+ * ocm_free() -+ * free a block in one of the ocm heaps, returns 0 if successful. -+ */ -+int ocm_free(const void *addr) -+{ -+ if (addr >= (void *)OCM_INST_HEAP_BEGIN -+ && addr < (void *)(OCM_INST_HEAP_END)) -+ return ocm_inst_free(addr); -+ else -+ return -1; -+} -+EXPORT_SYMBOL(ocm_free); -+ -+ -+#ifdef CONFIG_PROC_FS -+/* Need to keep line of output the same. Currently, that is 46 bytes -+ * (including newline). -+ */ -+static int _ocm_proc_read(char *buf, int *len, int count, const char *desc, -+ struct ocm_heap *ocmheap) -+{ -+ struct ocm_piece *pslot; -+ struct ocm_piece *pfree_head = &ocmheap->free_head; -+ struct ocm_piece *pused_head = &ocmheap->used_head; -+ -+ /* The format is the following -+ * --- OCM 123456789012345 Size PID State \n -+ * 12345678-12345678 1234567890 12345 1234567890\n -+ */ -+ int l; -+ l = sprintf(&buf[*len], "--- OCM %-15s Size PID State \n", -+ desc); -+ -+ *len += l; -+ count -= l; -+ -+ mutex_lock(&ocm_inst_heap.lock); -+ -+ /* -+ * search the relevant memory slot -+ */ -+ pslot = pused_head->next; -+ -+ while (pslot != NULL && count > 46) { -+ l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n", -+ pslot->paddr, pslot->paddr + pslot->size, -+ pslot->size, pslot->pid, "ALLOCATED"); -+ -+ *len += l; -+ count -= l; -+ pslot = pslot->next; -+ } -+ -+ pslot = pfree_head->next; -+ -+ while (pslot != NULL && count > 46) { -+ l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n", -+ pslot->paddr, pslot->paddr + pslot->size, -+ pslot->size, pslot->pid, "FREE"); -+ -+ *len += l; -+ count -= l; -+ pslot = pslot->next; -+ } -+ -+ mutex_unlock(&ocm_inst_heap.lock); -+ -+ return 0; -+} -+ -+static int ocm_proc_read(char *buf, char **start, off_t offset, int count, -+ int *eof, void *data) -+{ -+ int len = 0; -+ -+ len = sprintf(&buf[len], "--- OCM SKB usage (max RX buf %d)\n" -+ "(SKB in OCM) %d - (SKB in DDR) %d\n", -+ ubi32_ocm_skbuf_max, -+ ubi32_ocm_skbuf, -+ ubi32_ddr_skbuf); -+ -+ len += sprintf(&buf[len], "--- OCM Data Heap Size\n" -+ "%p-%p %10i\n", -+ ((void *)&__ocm_free_begin), -+ ((void *)&__ocm_free_end), -+ ((unsigned int)&__ocm_free_end) - -+ ((unsigned int)&__ocm_free_begin)); -+ -+ if (_ocm_proc_read(buf, &len, count - len, "Inst Heap", -+ &ocm_inst_heap)) -+ goto not_done; -+ *eof = 1; -+ not_done: -+ return len; -+} -+ -+static int ocm_proc_write(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ int n, v; -+ char in[8]; -+ -+ if (count > sizeof(in)) -+ return -EINVAL; -+ -+ if (copy_from_user(in, buffer, count)) -+ return -EFAULT; -+ in[count-1] = 0; -+ -+ printk(KERN_INFO "OCM skb alloc max = %s\n", in); -+ -+ n = 0; -+ v = 0; -+ while ((in[n] >= '0') && (in[n] <= '9')) { -+ v = v * 10 + (int)(in[n] - '0'); -+ n++; -+ } -+ -+ if (v == 0) -+ return -EINVAL; -+ -+ ubi32_ocm_skbuf_max = v; -+ ubi32_ocm_skbuf = ubi32_ddr_skbuf = 0; -+ -+ return count; -+} -+ -+static int __init sram_proc_init(void) -+{ -+ struct proc_dir_entry *ptr; -+ ptr = create_proc_entry("ocm", S_IFREG | S_IRUGO, NULL); -+ if (!ptr) { -+ printk(KERN_WARNING "unable to create /proc/ocm\n"); -+ return -1; -+ } -+ ptr->read_proc = ocm_proc_read; -+ ptr->write_proc = ocm_proc_write; -+ return 0; -+} -+late_initcall(sram_proc_init); -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/oprofile/ipProf.h linux-2.6.30.10-ubi/arch/ubicom32/oprofile/ipProf.h ---- linux-2.6.30.10/arch/ubicom32/oprofile/ipProf.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/oprofile/ipProf.h 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,39 @@ -+#ifndef __IP_PROF_H__ -+#define __IP_PROF_H__ -+ -+/* This number MUST match what is used in the ultra configuration! */ -+#define IPPROFILETIO_MAX_SAMPLES 600 -+ -+/* Move to .h file used in both; avoid special types */ -+struct profile_sample { -+ unsigned int pc; /* PC value */ -+ unsigned int parent; /* a5 contents, to find the caller */ -+ unsigned char cond_codes; /* for branch prediction */ -+ unsigned char thread; /* I-blocked, D-blocked, -+ 4-bit thread number */ -+ unsigned short active; /* which threads are active - -+ for accurate counting */ -+ unsigned short blocked; /* which threads are blocked due to -+ I or D cache misses */ -+ unsigned int latency; /* CPU clocks since the last message -+ dispatch in this thread -+ (thread 0 only for now) */ -+}; -+ -+ -+struct profilenode { -+ struct devtree_node dn; -+ volatile unsigned char enabled; /* Is the tio enabled to -+ take samples? */ -+ volatile unsigned char busy; /* set when the samples -+ are being read */ -+ volatile unsigned int mask; /* Threads that change the MT_EN flag */ -+ volatile unsigned short rate; /* What is the sampling rate? */ -+ volatile unsigned short head; /* sample taker puts samples here */ -+ volatile unsigned short tail; /* packet filler takes samples here */ -+ volatile unsigned short count; /* number of valid samples */ -+ volatile unsigned short total; /* Total samples */ -+ struct profile_sample samples[IPPROFILETIO_MAX_SAMPLES]; -+}; -+ -+#endif -diff -ruN linux-2.6.30.10/arch/ubicom32/oprofile/Makefile linux-2.6.30.10-ubi/arch/ubicom32/oprofile/Makefile ---- linux-2.6.30.10/arch/ubicom32/oprofile/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/oprofile/Makefile 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,37 @@ -+# -+# arch/ubicom32/Makefile -+# Makefile for Oprofile support on Ubicom32 -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+ -+obj-$(CONFIG_OPROFILE) += oprofile.o -+ -+DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ -+ oprof.o cpu_buffer.o buffer_sync.o \ -+ event_buffer.o oprofile_files.o \ -+ oprofilefs.o oprofile_stats.o \ -+ timer_int.o ) -+ -+oprofile-y := $(DRIVER_OBJS) profile.o -diff -ruN linux-2.6.30.10/arch/ubicom32/oprofile/profile.c linux-2.6.30.10-ubi/arch/ubicom32/oprofile/profile.c ---- linux-2.6.30.10/arch/ubicom32/oprofile/profile.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/arch/ubicom32/oprofile/profile.c 2009-12-11 11:45:11.000000000 +0200 -@@ -0,0 +1,221 @@ -+/* -+ * arch/ubicom32/oprofile/profile.c -+ * Oprofile support for arch Ubicom32 -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) -+ * any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it will -+ * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, see -+ * . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+/** -+ * @file profile.c -+ * -+ * @remark Copyright 2002 OProfile authors -+ * @remark Read the file COPYING -+ * -+ * @author Hunyue Yau -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* For identifying userland vs kernel address */ -+#include -+#include "ipProf.h" -+ -+/* For communications with the backend */ -+static struct profilenode *profile_node; -+ -+/* Bitmask containing all Linux threads - as seen by the ROSR reg */ -+static unsigned long th_all_mask; -+ -+/* Lookup table to translate a hardware thread into a CPU identifier -+ * Table is indexed by the ROSR value which is assumed to be -+ * relatively small (0...15). -+ */ -+unsigned int cpu_map[THREAD_ARCHITECTURAL_MAX]; -+ -+static struct pt_regs regs; -+ -+/* -+ * For each sample returned, checked to see if they are relevant to -+ * us. This is necessary as the ubicom32 architecture has other software -+ * running outside of Linux. Only then, put the sample into the relevant -+ * cpu bins. -+ * -+ * To minimize overhead, a global mask with all possible threads of in -+ * interest to us is used as a first check. Then a second mask identifying -+ * the thread is used to obtain an identifier for that "CPU". -+ */ -+ -+/* -+ * ubicom32_build_cpu_th_mask() -+ * -+ * Build a lookup table for translation between hardware thread -+ * "ROSR" values and Linux CPU ids -+ * -+ * *** This gets executed on all CPUs at once! *** -+ */ -+static void ubicom32_build_cpu_th_mask(void *mask) -+{ -+ thread_t self = thread_get_self(); -+ unsigned long *th_m = mask; -+ -+ BUG_ON(self <= 0 || self >= THREAD_ARCHITECTURAL_MAX); -+ cpu_map[self] = smp_processor_id(); -+ -+ set_bit(self, th_m); -+} -+ -+/* -+ * profile_interrupt() -+ * -+ * Process samples returned from the profiler backend. The backend -+ * may return samples that are irrelevant to us or may even return -+ * multiple samples for the same CPU. Note that the sames may be -+ * for ANY cpu. At this time, this is unique and to support this requires -+ * Oprofile to expose an interface to accept the CPU that the same came -+ * frome. -+ */ -+static irqreturn_t profile_interrupt(int irq, void *arg) -+{ -+ int i, buf_entry; -+ int is_kernel; -+ unsigned int bit_th; -+ unsigned int th; -+ -+ if (!(profile_node->enabled) || profile_node->count < 0) { -+ printk(KERN_WARNING -+ "Unexpected interrupt, no samples or not enabled!\n"); -+ return IRQ_HANDLED; -+ } -+ -+ profile_node->busy = 1; /* Keep backend out */ -+ -+ for (i = 0; i < profile_node->count; i++) { -+ buf_entry = profile_node->tail; -+ profile_node->tail++; -+ profile_node->tail %= IPPROFILETIO_MAX_SAMPLES; -+ -+ /* Note - the "thread" ID is only the lower 4 bits */ -+ th = (0x0f & profile_node->samples[buf_entry].thread); -+ bit_th = (1 << th); -+ -+ if ((bit_th & th_all_mask) == 0) -+ continue; -+ -+ regs.pc = profile_node->samples[buf_entry].pc; -+ -+ is_kernel = ubicom32_is_kernel(regs.pc); -+ -+ oprofile_add_ext_sample_cpu(regs.pc, ®s, 0, is_kernel, -+ cpu_map[th]); -+ } -+ profile_node->count = 0; -+ profile_node->busy = 0; -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * profile_start() -+ * -+ * Notification from oprofile to start the profiler -+ */ -+static int profile_start(void) -+{ -+ if (!profile_node) -+ return -1; -+ -+ profile_node->enabled = 1; -+ -+ return 0; -+} -+ -+/* -+ * profile_stop() -+ * -+ * Notification from oprofile to stop the profiler -+ */ -+static void profile_stop(void) -+{ -+ if (profile_node) -+ profile_node->enabled = 0; -+} -+ -+/* -+ * oprofile_arch_init() -+ * -+ * Attach to Oprofile after qualify the availability of the backend -+ * profiler support. -+ */ -+int __init oprofile_arch_init(struct oprofile_operations *ops) -+{ -+ int r = -ENODEV; -+ -+ profile_node = (struct profilenode *)devtree_find_node("profiler"); -+ -+ if (profile_node == NULL) { -+ printk(KERN_WARNING "Cannot find profiler node\n"); -+ return r; -+ } -+ -+ r = request_irq(profile_node->dn.recvirq, profile_interrupt, -+ IRQF_DISABLED, "profiler", NULL); -+ -+ if (r < 0) { -+ profile_node = NULL; -+ printk(KERN_WARNING "Cannot get profiler IRQ\n"); -+ return r; -+ } -+ -+ ops->start = profile_start; -+ ops->stop = profile_stop; -+ ops->cpu_type = "timer"; -+ -+ memset(cpu_map, 0, sizeof(cpu_map)); -+ -+ on_each_cpu(ubicom32_build_cpu_th_mask, &th_all_mask, 1); -+ -+ memset(®s, 0, sizeof(regs)); -+ -+ return r; -+} -+ -+/* -+ * oprofile_arch_exit() -+ * -+ * External call to take outselves out. -+ * Make sure backend is not running. -+ */ -+void oprofile_arch_exit(void) -+{ -+ BUG_ON(profile_node->enabled); -+} -diff -ruN linux-2.6.30.10/drivers/char/hw_random/Kconfig linux-2.6.30.10-ubi/drivers/char/hw_random/Kconfig ---- linux-2.6.30.10/drivers/char/hw_random/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/char/hw_random/Kconfig 2009-12-11 11:45:13.000000000 +0200 -@@ -148,3 +148,16 @@ +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -148,3 +148,16 @@ config HW_RANDOM_VIRTIO To compile this driver as a module, choose M here: the module will be called virtio-rng. If unsure, say N. @@ -41674,127 +17,16 @@ diff -ruN linux-2.6.30.10/drivers/char/hw_random/Kconfig linux-2.6.30.10-ubi/dri + module will be called pasemi-rng. + + If unsure, say Y. -diff -ruN linux-2.6.30.10/drivers/char/hw_random/Makefile linux-2.6.30.10-ubi/drivers/char/hw_random/Makefile ---- linux-2.6.30.10/drivers/char/hw_random/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/char/hw_random/Makefile 2009-12-11 11:45:13.000000000 +0200 -@@ -15,3 +15,4 @@ +--- a/drivers/char/hw_random/Makefile ++++ b/drivers/char/hw_random/Makefile +@@ -15,3 +15,4 @@ obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o +obj-$(CONFIG_HW_RANDOM_UBICOM32) += ubicom32-rng.o -diff -ruN linux-2.6.30.10/drivers/char/hw_random/ubicom32-rng.c linux-2.6.30.10-ubi/drivers/char/hw_random/ubicom32-rng.c ---- linux-2.6.30.10/drivers/char/hw_random/ubicom32-rng.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/char/hw_random/ubicom32-rng.c 2009-12-11 11:45:13.000000000 +0200 -@@ -0,0 +1,105 @@ -+/* -+ * drivers/net/ubi32-eth.c -+ * Ubicom32 hardware random number generator driver. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MODULE_NAME "ubicom32_rng" -+ -+static int ubicom32_rng_data_present(struct hwrng *rng, int wait) -+{ -+ int data, i; -+ -+ for (i = 0; i < 20; i++) { -+ data = *(int *)(TIMER_BASE + TIMER_TRN); -+ if (data || !wait) -+ break; -+ udelay(10); -+ } -+ return data; -+} -+ -+static int ubicom32_rng_data_read(struct hwrng *rng, u32 *data) -+{ -+ *data = *(int *)(TIMER_BASE + TIMER_TRN); -+ return 4; -+} -+ -+static int ubicom32_rng_init(struct hwrng *rng) -+{ -+ printk(KERN_INFO "ubicom32 rng init\n"); -+ *(int *)(TIMER_BASE + TIMER_TRN_CFG) = TIMER_TRN_CFG_ENABLE_OSC; -+ return 0; -+} -+ -+static void ubicom32_rng_cleanup(struct hwrng *rng) -+{ -+ printk(KERN_INFO "ubicom32 rng cleanup\n"); -+ *(int *)(TIMER_BASE + TIMER_TRN_CFG) = 0; -+} -+ -+static struct hwrng ubicom32_rng = { -+ .name = MODULE_NAME, -+ .init = ubicom32_rng_init, -+ .cleanup = ubicom32_rng_cleanup, -+ .data_present = ubicom32_rng_data_present, -+ .data_read = ubicom32_rng_data_read, -+ .priv = 0, -+}; -+ -+static int __init mod_init(void) -+{ -+ int err; -+ -+ printk(KERN_INFO "ubicom32 rng started\n"); -+ err = hwrng_register(&ubicom32_rng); -+ if (err) { -+ printk(KERN_ERR "ubicom32 rng register failed (%d)\n", -+ err); -+ } -+ -+ return err; -+} -+ -+static void __exit mod_exit(void) -+{ -+ printk(KERN_INFO "ubicom32 rng stopped\n"); -+ hwrng_unregister(&ubicom32_rng); -+} -+ -+module_init(mod_init); -+module_exit(mod_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Ubicom, Inc."); -+MODULE_DESCRIPTION("H/W rng driver for ubicom32 processor"); -+MODULE_VERSION("1:1.0.a"); -diff -ruN linux-2.6.30.10/drivers/crypto/Kconfig linux-2.6.30.10-ubi/drivers/crypto/Kconfig ---- linux-2.6.30.10/drivers/crypto/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/crypto/Kconfig 2009-12-11 11:45:13.000000000 +0200 -@@ -61,6 +61,40 @@ +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -61,6 +61,40 @@ config CRYPTO_DEV_GEODE To compile this driver as a module, choose M here: the module will be called geode-aes. @@ -41835,10 +67,9 @@ diff -ruN linux-2.6.30.10/drivers/crypto/Kconfig linux-2.6.30.10-ubi/drivers/cry config ZCRYPT tristate "Support for PCI-attached cryptographic adapters" depends on S390 -diff -ruN linux-2.6.30.10/drivers/mmc/host/Kconfig linux-2.6.30.10-ubi/drivers/mmc/host/Kconfig ---- linux-2.6.30.10/drivers/mmc/host/Kconfig 2009-12-14 11:15:33.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/mmc/host/Kconfig 2009-12-14 11:15:31.000000000 +0200 -@@ -266,3 +266,10 @@ +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -266,3 +266,10 @@ config GPIOMMC_CONFIGFS help This option automatically enables configfs support for gpiommc if configfs is available. @@ -41849,796 +80,17 @@ diff -ruN linux-2.6.30.10/drivers/mmc/host/Kconfig linux-2.6.30.10-ubi/drivers/m + help + This provides support for the SD/MMC hardware found on Ubicom32 + IP7K processors -diff -ruN linux-2.6.30.10/drivers/mmc/host/Makefile linux-2.6.30.10-ubi/drivers/mmc/host/Makefile ---- linux-2.6.30.10/drivers/mmc/host/Makefile 2009-12-14 11:37:36.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/mmc/host/Makefile 2009-12-14 11:37:35.000000000 +0200 -@@ -30,4 +30,5 @@ +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -30,4 +30,5 @@ obj-$(CONFIG_MMC_S3C) += s3cmci.o obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o obj-$(CONFIG_GPIOMMC) += gpiommc.o +obj-$(CONFIG_MMC_UBICOM32) += ubicom32sd.o -diff -ruN linux-2.6.30.10/drivers/mmc/host/ubicom32sd.c linux-2.6.30.10-ubi/drivers/mmc/host/ubicom32sd.c ---- linux-2.6.30.10/drivers/mmc/host/ubicom32sd.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/mmc/host/ubicom32sd.c 2009-12-11 11:45:16.000000000 +0200 -@@ -0,0 +1,773 @@ -+/* -+ * drivers/mmc/host/ubicom32sd.c -+ * Ubicom32 Secure Digital Host Controller Interface driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define DRIVER_NAME "ubicom32sd" -+ -+#define sd_printk(...) -+//#define sd_printk printk -+ -+#define SDTIO_VP_VERSION 3 -+ -+#define SDTIO_MAX_SG_BLOCKS 16 -+ -+enum sdtio_commands { -+ SDTIO_COMMAND_NOP, -+ SDTIO_COMMAND_SETUP, -+ SDTIO_COMMAND_SETUP_SDIO, -+ SDTIO_COMMAND_EXECUTE, -+ SDTIO_COMMAND_RESET, -+}; -+ -+#define SDTIO_COMMAND_SHIFT 24 -+#define SDTIO_COMMAND_FLAG_STOP_RSP_CRC (1 << 10) -+#define SDTIO_COMMAND_FLAG_STOP_RSP_136 (1 << 9) -+#define SDTIO_COMMAND_FLAG_STOP_RSP (1 << 8) -+#define SDTIO_COMMAND_FLAG_STOP_CMD (1 << 7) -+#define SDTIO_COMMAND_FLAG_DATA_STREAM (1 << 6) -+#define SDTIO_COMMAND_FLAG_DATA_RD (1 << 5) -+#define SDTIO_COMMAND_FLAG_DATA_WR (1 << 4) -+#define SDTIO_COMMAND_FLAG_CMD_RSP_CRC (1 << 3) -+#define SDTIO_COMMAND_FLAG_CMD_RSP_136 (1 << 2) -+#define SDTIO_COMMAND_FLAG_CMD_RSP (1 << 1) -+#define SDTIO_COMMAND_FLAG_CMD (1 << 0) -+ -+/* -+ * SDTIO_COMMAND_SETUP_SDIO -+ */ -+#define SDTIO_COMMAND_FLAG_SDIO_INT_EN (1 << 0) -+ -+/* -+ * SDTIO_COMMAND_SETUP -+ * clock speed in arg -+ */ -+#define SDTIO_COMMAND_FLAG_4BIT (1 << 3) -+#define SDTIO_COMMAND_FLAG_1BIT (1 << 2) -+#define SDTIO_COMMAND_FLAG_SET_CLOCK (1 << 1) -+#define SDTIO_COMMAND_FLAG_SET_WIDTH (1 << 0) -+ -+#define SDTIO_COMMAND_FLAG_CMD_RSP_MASK (SDTIO_COMMAND_FLAG_CMD_RSP | SDTIO_COMMAND_FLAG_CMD_RSP_136) -+#define SDTIO_COMMAND_FLAG_STOP_RSP_MASK (SDTIO_COMMAND_FLAG_STOP_RSP | SDTIO_COMMAND_FLAG_STOP_RSP_136) -+#define SDTIO_COMMAND_FLAG_RSP_MASK (SDTIO_COMMAND_FLAG_CMD_RSP_MASK | SDTIO_COMMAND_FLAG_STOP_RSP_MASK) -+ -+struct sdtio_vp_sg { -+ volatile void *addr; -+ volatile u32_t len; -+}; -+ -+#define SDTIO_VP_INT_STATUS_DONE (1 << 31) -+#define SDTIO_VP_INT_STATUS_SDIO_INT (1 << 10) -+#define SDTIO_VP_INT_STATUS_DATA_CRC_ERR (1 << 9) -+#define SDTIO_VP_INT_STATUS_DATA_PROG_ERR (1 << 8) -+#define SDTIO_VP_INT_STATUS_DATA_TIMEOUT (1 << 7) -+#define SDTIO_VP_INT_STATUS_STOP_RSP_CRC (1 << 6) -+#define SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT (1 << 5) -+#define SDTIO_VP_INT_STATUS_CMD_RSP_CRC (1 << 4) -+#define SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT (1 << 3) -+#define SDTIO_VP_INT_STATUS_CMD_TIMEOUT (1 << 2) -+#define SDTIO_VP_INT_STATUS_CARD1_INSERT (1 << 1) -+#define SDTIO_VP_INT_STATUS_CARD0_INSERT (1 << 0) -+ -+struct sdtio_vp_regs { -+ u32_t version; -+ u32_t f_max; -+ u32_t f_min; -+ -+ volatile u32_t int_status; -+ -+ volatile u32_t command; -+ volatile u32_t arg; -+ -+ volatile u32_t cmd_opcode; -+ volatile u32_t cmd_arg; -+ volatile u32_t cmd_rsp0; -+ volatile u32_t cmd_rsp1; -+ volatile u32_t cmd_rsp2; -+ volatile u32_t cmd_rsp3; -+ -+ volatile u32_t stop_opcode; -+ volatile u32_t stop_arg; -+ volatile u32_t stop_rsp0; -+ volatile u32_t stop_rsp1; -+ volatile u32_t stop_rsp2; -+ volatile u32_t stop_rsp3; -+ -+ volatile u32_t data_timeout_ns; -+ volatile u16_t data_blksz; -+ volatile u16_t data_blkct; -+ volatile u32_t data_bytes_transferred; -+ volatile u32_t sg_len; -+ struct sdtio_vp_sg sg[SDTIO_MAX_SG_BLOCKS]; -+}; -+ -+struct ubicom32sd_data { -+ const struct ubicom32sd_platform_data *pdata; -+ -+ struct mmc_host *mmc; -+ -+ /* -+ * Lock used to protect the data structure -+ spinlock_t lock; -+ */ -+ int int_en; -+ int int_pend; -+ -+ /* -+ * Receive and transmit interrupts used for communicating -+ * with hardware -+ */ -+ int irq_tx; -+ int irq_rx; -+ -+ /* -+ * Current outstanding mmc request -+ */ -+ struct mmc_request *mrq; -+ -+ /* -+ * Hardware registers -+ */ -+ struct sdtio_vp_regs *regs; -+}; -+ -+/*****************************************************************************\ -+ * * -+ * Suspend/resume * -+ * * -+\*****************************************************************************/ -+ -+#if 0//def CONFIG_PM -+ -+int ubicom32sd_suspend_host(struct ubicom32sd_host *host, pm_message_t state) -+{ -+ int ret; -+ -+ ret = mmc_suspend_host(host->mmc, state); -+ if (ret) -+ return ret; -+ -+ free_irq(host->irq, host); -+ -+ return 0; -+} -+ -+EXPORT_SYMBOL_GPL(ubicom32sd_suspend_host); -+ -+int ubicom32sd_resume_host(struct ubicom32sd_host *host) -+{ -+ int ret; -+ -+ if (host->flags & UBICOM32SD_USE_DMA) { -+ if (host->ops->enable_dma) -+ host->ops->enable_dma(host); -+ } -+ -+ ret = request_irq(host->irq, ubicom32sd_irq, IRQF_SHARED, -+ mmc_hostname(host->mmc), host); -+ if (ret) -+ return ret; -+ -+ ubicom32sd_init(host); -+ mmiowb(); -+ -+ ret = mmc_resume_host(host->mmc); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+EXPORT_SYMBOL_GPL(ubicom32sd_resume_host); -+ -+#endif /* CONFIG_PM */ -+ -+/* -+ * ubicom32sd_send_command_sync -+ */ -+static void ubicom32sd_send_command_sync(struct ubicom32sd_data *ud, u32_t command, u32_t arg) -+{ -+ ud->regs->command = command; -+ ud->regs->arg = arg; -+ ubicom32_set_interrupt(ud->irq_tx); -+ while (ud->regs->command) { -+ ndelay(100); -+ } -+} -+ -+/* -+ * ubicom32sd_send_command -+ */ -+static void ubicom32sd_send_command(struct ubicom32sd_data *ud, u32_t command, u32_t arg) -+{ -+ ud->regs->command = command; -+ ud->regs->arg = arg; -+ ubicom32_set_interrupt(ud->irq_tx); -+} -+ -+/* -+ * ubicom32sd_reset -+ */ -+static void ubicom32sd_reset(struct ubicom32sd_data *ud) -+{ -+ ubicom32sd_send_command_sync(ud, SDTIO_COMMAND_RESET << SDTIO_COMMAND_SHIFT, 0); -+ ud->regs->int_status = 0; -+} -+ -+/* -+ * ubicom32sd_mmc_request -+ */ -+static void ubicom32sd_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); -+ u32_t command = SDTIO_COMMAND_EXECUTE << SDTIO_COMMAND_SHIFT; -+ int ret = 0; -+ -+ WARN(ud->mrq != NULL, "ud->mrq still set to %p\n", ud->mrq); -+ //pr_debug("send cmd %08x arg %08x flags %08x\n", cmd->opcode, cmd->arg, cmd->flags); -+ -+ if (mrq->cmd) { -+ struct mmc_command *cmd = mrq->cmd; -+ -+ sd_printk("%s:\t\t\tsetup cmd %02d arg %08x flags %08x\n", mmc_hostname(mmc), cmd->opcode, cmd->arg, cmd->flags); -+ -+ ud->regs->cmd_opcode = cmd->opcode; -+ ud->regs->cmd_arg = cmd->arg; -+ -+ command |= SDTIO_COMMAND_FLAG_CMD; -+ -+ if (cmd->flags & MMC_RSP_PRESENT) { -+ command |= SDTIO_COMMAND_FLAG_CMD_RSP; -+ } -+ -+ if (cmd->flags & MMC_RSP_136) { -+ command |= SDTIO_COMMAND_FLAG_CMD_RSP_136; -+ } -+ -+ if (cmd->flags & MMC_RSP_CRC) { -+ command |= SDTIO_COMMAND_FLAG_CMD_RSP_CRC; -+ } -+ } -+ -+ if (mrq->data) { -+ struct mmc_data *data = mrq->data; -+ struct scatterlist *sg = data->sg; -+ int i; -+ -+printk("%s:\t\t\tsetup data blksz %d num %d sglen=%d fl=%08x Tns=%u\n", mmc_hostname(mmc), data->blksz, data->blocks, data->sg_len, data->flags, data->timeout_ns); -+ -+ sd_printk("%s:\t\t\tsetup data blksz %d num %d sglen=%d fl=%08x Tns=%u\n", -+ mmc_hostname(mmc), data->blksz, data->blocks, data->sg_len, -+ data->flags, data->timeout_ns); -+ -+ if (data->sg_len > SDTIO_MAX_SG_BLOCKS) { -+ ret = -EINVAL; -+ data->error = -EINVAL; -+ goto fail; -+ } -+ -+ ud->regs->data_timeout_ns = data->timeout_ns; -+ ud->regs->data_blksz = data->blksz; -+ ud->regs->data_blkct = data->blocks; -+ ud->regs->sg_len = data->sg_len; -+ -+ /* -+ * Load all of our sg list into the driver sg buffer -+ */ -+ for (i = 0; i < data->sg_len; i++) { -+ sd_printk("%s: sg %d = %p %d\n", mmc_hostname(mmc), i, sg_virt(sg), sg->length); -+ ud->regs->sg[i].addr = sg_virt(sg); -+ ud->regs->sg[i].len = sg->length; -+ if (((u32_t)ud->regs->sg[i].addr & 0x03) || (sg->length & 0x03)) { -+ sd_printk("%s: Need aligned buffers\n", mmc_hostname(mmc)); -+ ret = -EINVAL; -+ data->error = -EINVAL; -+ goto fail; -+ } -+ sg++; -+ } -+ if (data->flags & MMC_DATA_READ) { -+ command |= SDTIO_COMMAND_FLAG_DATA_RD; -+ } else if (data->flags & MMC_DATA_WRITE) { -+ command |= SDTIO_COMMAND_FLAG_DATA_WR; -+ } else if (data->flags & MMC_DATA_STREAM) { -+ command |= SDTIO_COMMAND_FLAG_DATA_STREAM; -+ } -+ } -+ -+ if (mrq->stop) { -+ struct mmc_command *stop = mrq->stop; -+ sd_printk("%s: \t\t\tsetup stop %02d arg %08x flags %08x\n", mmc_hostname(mmc), stop->opcode, stop->arg, stop->flags); -+ -+ ud->regs->stop_opcode = stop->opcode; -+ ud->regs->stop_arg = stop->arg; -+ -+ command |= SDTIO_COMMAND_FLAG_STOP_CMD; -+ -+ if (stop->flags & MMC_RSP_PRESENT) { -+ command |= SDTIO_COMMAND_FLAG_STOP_RSP; -+ } -+ -+ if (stop->flags & MMC_RSP_136) { -+ command |= SDTIO_COMMAND_FLAG_STOP_RSP_136; -+ } -+ -+ if (stop->flags & MMC_RSP_CRC) { -+ command |= SDTIO_COMMAND_FLAG_STOP_RSP_CRC; -+ } -+ } -+ -+ ud->mrq = mrq; -+ -+ sd_printk("%s: Sending command %08x\n", mmc_hostname(mmc), command); -+ -+ ubicom32sd_send_command(ud, command, 0); -+ -+ return; -+fail: -+ sd_printk("%s: mmcreq ret = %d\n", mmc_hostname(mmc), ret); -+ mrq->cmd->error = ret; -+ mmc_request_done(mmc, mrq); -+} -+ -+/* -+ * ubicom32sd_mmc_set_ios -+ */ -+static void ubicom32sd_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -+{ -+ struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); -+ u32_t command = SDTIO_COMMAND_SETUP << SDTIO_COMMAND_SHIFT; -+ u32_t arg = 0; -+ sd_printk("%s: ios call bw:%u pm:%u clk:%u\n", mmc_hostname(mmc), 1 << ios->bus_width, ios->power_mode, ios->clock); -+ -+ switch (ios->bus_width) { -+ case MMC_BUS_WIDTH_1: -+ command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_1BIT; -+ break; -+ -+ case MMC_BUS_WIDTH_4: -+ command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_4BIT; -+ break; -+ } -+ -+ if (ios->clock) { -+ arg = ios->clock; -+ command |= SDTIO_COMMAND_FLAG_SET_CLOCK; -+ } -+ -+ switch (ios->power_mode) { -+ -+ /* -+ * Turn off the SD bus (power + clock) -+ */ -+ case MMC_POWER_OFF: -+ gpio_set_value(ud->pdata->cards[0].pin_pwr, !ud->pdata->cards[0].pwr_polarity); -+ command |= SDTIO_COMMAND_FLAG_SET_CLOCK; -+ break; -+ -+ /* -+ * Turn on the power to the SD bus -+ */ -+ case MMC_POWER_ON: -+ gpio_set_value(ud->pdata->cards[0].pin_pwr, ud->pdata->cards[0].pwr_polarity); -+ break; -+ -+ /* -+ * Turn on the clock to the SD bus -+ */ -+ case MMC_POWER_UP: -+ /* -+ * Done above -+ */ -+ break; -+ } -+ -+ ubicom32sd_send_command_sync(ud, command, arg); -+ -+ /* -+ * Let the power settle down -+ */ -+ udelay(500); -+} -+ -+/* -+ * ubicom32sd_mmc_get_cd -+ */ -+static int ubicom32sd_mmc_get_cd(struct mmc_host *mmc) -+{ -+ struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); -+ sd_printk("%s: get cd %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_cd, gpio_get_value(ud->pdata->cards[0].pin_cd)); -+ -+ return gpio_get_value(ud->pdata->cards[0].pin_cd) ? -+ ud->pdata->cards[0].cd_polarity : -+ !ud->pdata->cards[0].cd_polarity; -+} -+ -+/* -+ * ubicom32sd_mmc_get_ro -+ */ -+static int ubicom32sd_mmc_get_ro(struct mmc_host *mmc) -+{ -+ struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); -+ sd_printk("%s: get ro %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_wp, gpio_get_value(ud->pdata->cards[0].pin_wp)); -+ -+ return gpio_get_value(ud->pdata->cards[0].pin_wp) ? -+ ud->pdata->cards[0].wp_polarity : -+ !ud->pdata->cards[0].wp_polarity; -+} -+ -+/* -+ * ubicom32sd_mmc_enable_sdio_irq -+ */ -+static void ubicom32sd_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) -+{ -+ struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); -+ -+ ud->int_en = enable; -+ if (enable && ud->int_pend) { -+ ud->int_pend = 0; -+ mmc_signal_sdio_irq(mmc); -+ } -+} -+ -+/* -+ * ubicom32sd_interrupt -+ */ -+static irqreturn_t ubicom32sd_interrupt(int irq, void *dev) -+{ -+ struct mmc_host *mmc = (struct mmc_host *)dev; -+ struct mmc_request *mrq; -+ struct ubicom32sd_data *ud; -+ u32_t int_status; -+ -+ if (!mmc) { -+ return IRQ_HANDLED; -+ } -+ -+ ud = (struct ubicom32sd_data *)mmc_priv(mmc); -+ if (!ud) { -+ return IRQ_HANDLED; -+ } -+ -+ int_status = ud->regs->int_status; -+ ud->regs->int_status &= ~int_status; -+ -+ if (int_status & SDTIO_VP_INT_STATUS_SDIO_INT) { -+ if (ud->int_en) { -+ ud->int_pend = 0; -+ mmc_signal_sdio_irq(mmc); -+ } else { -+ ud->int_pend++; -+ } -+ } -+ -+ if (!(int_status & SDTIO_VP_INT_STATUS_DONE)) { -+ return IRQ_HANDLED; -+ } -+ -+ mrq = ud->mrq; -+ if (!mrq) { -+ sd_printk("%s: Spurious interrupt", mmc_hostname(mmc)); -+ return IRQ_HANDLED; -+ } -+ ud->mrq = NULL; -+ -+ /* -+ * SDTIO_VP_INT_DONE -+ */ -+ if (mrq->cmd->flags & MMC_RSP_PRESENT) { -+ struct mmc_command *cmd = mrq->cmd; -+ cmd->error = 0; -+ -+ if ((cmd->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_CRC)) { -+ cmd->error = -EILSEQ; -+ } else if (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT) { -+ cmd->error = -ETIMEDOUT; -+ goto done; -+ } else if (cmd->flags & MMC_RSP_136) { -+ cmd->resp[0] = ud->regs->cmd_rsp0; -+ cmd->resp[1] = ud->regs->cmd_rsp1; -+ cmd->resp[2] = ud->regs->cmd_rsp2; -+ cmd->resp[3] = ud->regs->cmd_rsp3; -+ } else { -+ cmd->resp[0] = ud->regs->cmd_rsp0; -+ } -+ sd_printk("%s:\t\t\tResponse %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); -+ } -+ -+ if (mrq->data) { -+ struct mmc_data *data = mrq->data; -+ -+ if (int_status & SDTIO_VP_INT_STATUS_DATA_TIMEOUT) { -+ data->error = -ETIMEDOUT; -+ sd_printk("%s:\t\t\tData Timeout\n", mmc_hostname(mmc)); -+ goto done; -+ } else if (int_status & SDTIO_VP_INT_STATUS_DATA_CRC_ERR) { -+ data->error = -EILSEQ; -+ sd_printk("%s:\t\t\tData CRC\n", mmc_hostname(mmc)); -+ goto done; -+ } else if (int_status & SDTIO_VP_INT_STATUS_DATA_PROG_ERR) { -+ data->error = -EILSEQ; -+ sd_printk("%s:\t\t\tData Program Error\n", mmc_hostname(mmc)); -+ goto done; -+ } else { -+ data->error = 0; -+ data->bytes_xfered = ud->regs->data_bytes_transferred; -+ } -+ } -+ -+ if (mrq->stop && (mrq->stop->flags & MMC_RSP_PRESENT)) { -+ struct mmc_command *stop = mrq->stop; -+ stop->error = 0; -+ -+ if ((stop->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_CRC)) { -+ stop->error = -EILSEQ; -+ } else if (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT) { -+ stop->error = -ETIMEDOUT; -+ goto done; -+ } else if (stop->flags & MMC_RSP_136) { -+ stop->resp[0] = ud->regs->stop_rsp0; -+ stop->resp[1] = ud->regs->stop_rsp1; -+ stop->resp[2] = ud->regs->stop_rsp2; -+ stop->resp[3] = ud->regs->stop_rsp3; -+ } else { -+ stop->resp[0] = ud->regs->stop_rsp0; -+ } -+ sd_printk("%s:\t\t\tStop Response %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), stop->resp[0], stop->resp[1], stop->resp[2], stop->resp[3], stop->error); -+ } -+ -+done: -+ mmc_request_done(mmc, mrq); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct mmc_host_ops ubicom32sd_ops = { -+ .request = ubicom32sd_mmc_request, -+ .set_ios = ubicom32sd_mmc_set_ios, -+ .get_ro = ubicom32sd_mmc_get_ro, -+ .get_cd = ubicom32sd_mmc_get_cd, -+ .enable_sdio_irq = ubicom32sd_mmc_enable_sdio_irq, -+}; -+ -+/* -+ * ubicom32sd_probe -+ */ -+static int __devinit ubicom32sd_probe(struct platform_device *pdev) -+{ -+ struct ubicom32sd_platform_data *pdata = (struct ubicom32sd_platform_data *)pdev->dev.platform_data; -+ struct mmc_host *mmc; -+ struct ubicom32sd_data *ud; -+ struct resource *res_regs; -+ struct resource *res_irq_tx; -+ struct resource *res_irq_rx; -+ int ret; -+ -+ /* -+ * Get our resources, regs is the hardware driver base address -+ * and the tx and rx irqs are used to communicate with the -+ * hardware driver. -+ */ -+ res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -+ res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1); -+ if (!res_regs || !res_irq_tx || !res_irq_rx) { -+ ret = -EINVAL; -+ goto fail; -+ } -+ -+ /* -+ * Reserve any gpios we need -+ */ -+ ret = gpio_request(pdata->cards[0].pin_wp, "sd-wp"); -+ if (ret) { -+ goto fail; -+ } -+ gpio_direction_input(pdata->cards[0].pin_wp); -+ -+ ret = gpio_request(pdata->cards[0].pin_cd, "sd-cd"); -+ if (ret) { -+ goto fail_cd; -+ } -+ gpio_direction_input(pdata->cards[0].pin_cd); -+ -+ /* -+ * HACK: for the dual port controller on port F, we don't support the second port right now -+ */ -+ if (pdata->ncards > 1) { -+ ret = gpio_request(pdata->cards[1].pin_pwr, "sd-pwr"); -+ gpio_direction_output(pdata->cards[1].pin_pwr, !pdata->cards[1].pwr_polarity); -+ gpio_direction_output(pdata->cards[1].pin_pwr, pdata->cards[1].pwr_polarity); -+ } -+ -+ ret = gpio_request(pdata->cards[0].pin_pwr, "sd-pwr"); -+ if (ret) { -+ goto fail_pwr; -+ } -+ gpio_direction_output(pdata->cards[0].pin_pwr, !pdata->cards[0].pwr_polarity); -+ -+ /* -+ * Allocate the MMC driver, it includes memory for our data. -+ */ -+ mmc = mmc_alloc_host(sizeof(struct ubicom32sd_data), &pdev->dev); -+ if (!mmc) { -+ ret = -ENOMEM; -+ goto fail_mmc; -+ } -+ ud = (struct ubicom32sd_data *)mmc_priv(mmc); -+ ud->mmc = mmc; -+ ud->pdata = pdata; -+ ud->regs = (struct sdtio_vp_regs *)res_regs->start; -+ ud->irq_tx = res_irq_tx->start; -+ ud->irq_rx = res_irq_rx->start; -+ platform_set_drvdata(pdev, mmc); -+ -+ ret = request_irq(ud->irq_rx, ubicom32sd_interrupt, IRQF_DISABLED, mmc_hostname(mmc), mmc); -+ if (ret) { -+ goto fail_mmc; -+ } -+ -+ /* -+ * Fill in the mmc structure -+ */ -+ mmc->ops = &ubicom32sd_ops; -+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL | MMC_CAP_SDIO_IRQ | -+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; -+ -+ mmc->f_min = ud->regs->f_min; -+ mmc->f_max = ud->regs->f_max; -+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; -+ -+ /* -+ * Setup some restrictions on transfers -+ * -+ * We allow up to SDTIO_MAX_SG_BLOCKS of data to DMA into, there are -+ * not really any "max_seg_size", "max_req_size", or "max_blk_count" -+ * restrictions (must be less than U32_MAX though), pick -+ * something large?!... -+ * -+ * The hardware can do up to 4095 bytes per block, since the spec -+ * only requires 2048, we'll set it to that and not worry about -+ * potential weird blk lengths. -+ */ -+ mmc->max_hw_segs = SDTIO_MAX_SG_BLOCKS; -+ mmc->max_phys_segs = SDTIO_MAX_SG_BLOCKS; -+ mmc->max_seg_size = 1024 * 1024; -+ mmc->max_req_size = 1024 * 1024; -+ mmc->max_blk_count = 1024; -+ -+ mmc->max_blk_size = 2048; -+ -+ ubicom32sd_reset(ud); -+ -+ /* -+ * enable interrupts -+ */ -+ ud->int_en = 0; -+ ubicom32sd_send_command_sync(ud, SDTIO_COMMAND_SETUP_SDIO << SDTIO_COMMAND_SHIFT | SDTIO_COMMAND_FLAG_SDIO_INT_EN, 0); -+ -+ mmc_add_host(mmc); -+ -+ printk(KERN_INFO "%s at %p, irq %d/%d\n", mmc_hostname(mmc), -+ ud->regs, ud->irq_tx, ud->irq_rx); -+ return 0; -+ -+fail_mmc: -+ gpio_free(pdata->cards[0].pin_pwr); -+fail_pwr: -+ gpio_free(pdata->cards[0].pin_cd); -+fail_cd: -+ gpio_free(pdata->cards[0].pin_wp); -+fail: -+ return ret; -+} -+ -+/* -+ * ubicom32sd_remove -+ */ -+static int __devexit ubicom32sd_remove(struct platform_device *pdev) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(pdev); -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ if (mmc) { -+ struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); -+ -+ gpio_free(ud->pdata->cards[0].pin_pwr); -+ gpio_free(ud->pdata->cards[0].pin_cd); -+ gpio_free(ud->pdata->cards[0].pin_wp); -+ -+ mmc_remove_host(mmc); -+ mmc_free_host(mmc); -+ } -+ -+ /* -+ * Note that our data is allocated as part of the mmc structure -+ * so we don't need to free it. -+ */ -+ return 0; -+} -+ -+static struct platform_driver ubicom32sd_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ .probe = ubicom32sd_probe, -+ .remove = __devexit_p(ubicom32sd_remove), -+#if 0 -+ .suspend = ubicom32sd_suspend, -+ .resume = ubicom32sd_resume, -+#endif -+}; -+ -+/* -+ * ubicom32sd_init -+ */ -+static int __init ubicom32sd_init(void) -+{ -+ return platform_driver_register(&ubicom32sd_driver); -+} -+module_init(ubicom32sd_init); -+ -+/* -+ * ubicom32sd_exit -+ */ -+static void __exit ubicom32sd_exit(void) -+{ -+ platform_driver_unregister(&ubicom32sd_driver); -+} -+module_exit(ubicom32sd_exit); -+ -+MODULE_AUTHOR("Patrick Tjin"); -+MODULE_DESCRIPTION("Ubicom32 Secure Digital Host Controller Interface driver"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/drivers/mtd/devices/Kconfig linux-2.6.30.10-ubi/drivers/mtd/devices/Kconfig ---- linux-2.6.30.10/drivers/mtd/devices/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/mtd/devices/Kconfig 2009-12-11 11:45:16.000000000 +0200 -@@ -104,6 +104,31 @@ +--- a/drivers/mtd/devices/Kconfig ++++ b/drivers/mtd/devices/Kconfig +@@ -104,6 +104,31 @@ config M25PXX_USE_FAST_READ help This option enables FAST_READ access supported by ST M25Pxx. @@ -42670,3303 +122,18 @@ diff -ruN linux-2.6.30.10/drivers/mtd/devices/Kconfig linux-2.6.30.10-ubi/driver config MTD_SLRAM tristate "Uncached system RAM" help -diff -ruN linux-2.6.30.10/drivers/mtd/devices/Makefile linux-2.6.30.10-ubi/drivers/mtd/devices/Makefile ---- linux-2.6.30.10/drivers/mtd/devices/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/mtd/devices/Makefile 2009-12-11 11:45:16.000000000 +0200 -@@ -16,3 +16,6 @@ +--- a/drivers/mtd/devices/Makefile ++++ b/drivers/mtd/devices/Makefile +@@ -16,3 +16,6 @@ obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o +obj-$(CONFIG_MTD_UBI32_M25P80) += ubi32-m25p80.o +obj-$(CONFIG_MTD_NAND_SPI_ER) += nand-spi-er.o +obj-$(CONFIG_MTD_UBI32_NAND_SPI_ER) += ubi32-nand-spi-er.o -diff -ruN linux-2.6.30.10/drivers/mtd/devices/nand-spi-er.c linux-2.6.30.10-ubi/drivers/mtd/devices/nand-spi-er.c ---- linux-2.6.30.10/drivers/mtd/devices/nand-spi-er.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/mtd/devices/nand-spi-er.c 2009-12-11 11:45:16.000000000 +0200 -@@ -0,0 +1,1017 @@ -+/* -+ * Micron SPI-ER NAND Flash Memory -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+*/ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+#define NAND_SPI_ER_BLOCK_FROM_ROW(row) (row >> 6) -+ -+#define NAND_SPI_ER_STATUS_P_FAIL (1 << 3) -+#define NAND_SPI_ER_STATUS_E_FAIL (1 << 2) -+#define NAND_SPI_ER_STATUS_OIP (1 << 0) -+ -+#define NAND_SPI_ER_LAST_ROW_INVALID 0xFFFFFFFF -+#define NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET 0x08 -+ -+struct nand_spi_er_device { -+ const char *name; -+ -+ uint8_t id0; -+ uint8_t id1; -+ -+ unsigned int blocks; -+ unsigned int pages_per_block; -+ unsigned int page_size; -+ unsigned int write_size; -+ unsigned int erase_size; -+}; -+ -+struct nand_spi_er { -+ char name[24]; -+ -+ const struct nand_spi_er_device *device; -+ -+ struct mutex lock; -+ struct spi_device *spi; -+ -+ struct mtd_info mtd; -+ -+ unsigned int last_row; /* the last row we fetched */ -+ -+ /* -+ * Bad block table (MUST be last in strcuture) -+ */ -+ unsigned long nbb; -+ unsigned long bbt[0]; -+}; -+ -+const struct nand_spi_er_device nand_spi_er_devices[] = { -+ { -+ name: "MT29F1G01ZDC", -+ id0: 0x2C, -+ id1: 0x12, -+ blocks: 1024, -+ pages_per_block: 64, -+ page_size: 2048, -+ write_size: 512, -+ erase_size: 64 * 2048, -+ }, -+ { -+ name: "MT29F1G01ZDC", -+ id0: 0x2C, -+ id1: 0x13, -+ blocks: 1024, -+ pages_per_block: 64, -+ page_size: 2048, -+ write_size: 512, -+ erase_size: 64 * 2048, -+ }, -+}; -+ -+static int read_only = 0; -+module_param(read_only, int, 0); -+MODULE_PARM_DESC(read_only, "Leave device locked"); -+ -+/* -+ * nand_spi_er_get_feature -+ * Get Feature register -+ */ -+static int nand_spi_er_get_feature(struct nand_spi_er *chip, int reg, uint8_t *data) -+{ -+ uint8_t txbuf[2]; -+ uint8_t rxbuf[1]; -+ int res; -+ -+ txbuf[0] = 0x0F; -+ txbuf[1] = reg; -+ res = spi_write_then_read(chip->spi, txbuf, 2, rxbuf, 1); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed get feature res=%d\n", chip->name, res); -+ return res; -+ } -+ *data = rxbuf[0]; -+ return 0; -+} -+ -+/* -+ * nand_spi_er_busywait -+ * Wait until the chip is not busy -+ */ -+static int nand_spi_er_busywait(struct nand_spi_er *chip, uint8_t *data) -+{ -+ int i; -+ -+ for (i = 0; i < 100; i++) { -+ int res = nand_spi_er_get_feature(chip, 0xC0, data); -+ if (res) { -+ return res; -+ } -+ if (!(*data & NAND_SPI_ER_STATUS_OIP)) { -+ break; -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * nand_spi_er_erase -+ * Erase a block, parameters must be block aligned -+ */ -+static int nand_spi_er_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ struct nand_spi_er *chip = mtd->priv; -+ struct spi_device *spi = chip->spi; -+ uint8_t txbuf[4]; -+ int res; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: erase addr:%x len:%x\n", chip->name, instr->addr, instr->len); -+ -+ if ((instr->addr + instr->len) > mtd->size) { -+ return -EINVAL; -+ } -+ -+ if (instr->addr & (chip->device->erase_size - 1)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: erase address is not aligned %x\n", chip->name, instr->addr); -+ return -EINVAL; -+ } -+ -+ if (instr->len & (chip->device->erase_size - 1)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: erase len is not aligned %x\n", chip->name, instr->len); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&chip->lock); -+ chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; -+ -+ while (instr->len) { -+ uint32_t block = instr->addr >> 17; -+ uint32_t row = block << 6; -+ uint8_t stat; -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: block erase row:%x block:%x addr:%x rem:%x\n", chip->name, row, block, instr->addr, instr->len); -+ -+ /* -+ * Write enable -+ */ -+ txbuf[0] = 0x06; -+ res = spi_write(spi, txbuf, 1); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res); -+ mutex_unlock(&chip->lock); -+ return res; -+ } -+ -+ /* -+ * Test for bad block -+ */ -+ if (test_bit(block, chip->bbt)) { -+ instr->fail_addr = block << 17; -+ instr->state = MTD_ERASE_FAILED; -+ res = -EBADMSG; -+ goto done; -+ } -+ -+ /* -+ * Block erase -+ */ -+ txbuf[0] = 0xD8; -+ txbuf[1] = 0x00; -+ txbuf[2] = row >> 8; -+ txbuf[3] = row & 0xFF; -+ res = spi_write(spi, txbuf, 4); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed block erase res=%d\n", chip->name, res); -+ instr->fail_addr = block << 17; -+ instr->state = MTD_ERASE_FAILED; -+ goto done; -+ } -+ -+ /* -+ * Wait -+ */ -+ res = nand_spi_er_busywait(chip, &stat); -+ if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { -+ instr->fail_addr = block << 17; -+ instr->state = MTD_ERASE_FAILED; -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); -+ if (res) { -+ goto done; -+ } -+ -+ /* -+ * Chip is stuck? -+ */ -+ res = -EIO; -+ goto done; -+ } -+ -+ /* -+ * Check the status register -+ */ -+ if (stat & NAND_SPI_ER_STATUS_E_FAIL) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: E_FAIL signalled (%02x)\n", chip->name, stat); -+ instr->fail_addr = block << 17; -+ instr->state = MTD_ERASE_FAILED; -+ goto done; -+ } -+ -+ /* -+ * Next -+ */ -+ block++; -+ instr->len -= chip->device->erase_size; -+ instr->addr += chip->device->erase_size; -+ } -+ -+ instr->state = MTD_ERASE_DONE; -+ -+ mutex_unlock(&chip->lock); -+ return 0; -+ -+done: -+ /* -+ * Write disable -+ */ -+ txbuf[0] = 0x04; -+ res = spi_write(spi, txbuf, 1); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res); -+ } -+ -+ mutex_unlock(&chip->lock); -+ -+ mtd_erase_callback(instr); -+ return 0; -+} -+ -+/* -+ * nand_spi_er_read -+ * -+ * return -EUCLEAN: ecc error recovered -+ * return -EBADMSG: ecc error not recovered -+*/ -+static int nand_spi_er_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ struct nand_spi_er *chip = mtd->priv; -+ struct spi_device *spi = chip->spi; -+ -+ uint32_t row; -+ uint32_t column; -+ int retval = 0; -+ -+ *retlen = 0; -+ DEBUG(MTD_DEBUG_LEVEL2, "%s: read block from %llx len %d into %p\n", chip->name, from, len, buf); -+ -+ /* -+ * Zero length reads, nothing to do -+ */ -+ if (len == 0) { -+ return 0; -+ } -+ -+ /* -+ * Reject reads which go over the end of the flash -+ */ -+ if ((from + len) > mtd->size) { -+ return -EINVAL; -+ } -+ -+ /* -+ * Get the row and column address to start at -+ */ -+ row = from >> 11; -+ column = from & 0x7FF; -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: row=%x %d column=%x %d last_row=%x %d\n", chip->name, row, row, column, column, chip->last_row, chip->last_row); -+ -+ /* -+ * Read the data from the chip -+ */ -+ mutex_lock(&chip->lock); -+ while (len) { -+ uint8_t stat; -+ uint8_t txbuf[4]; -+ struct spi_message message; -+ struct spi_transfer x[2]; -+ int res; -+ size_t toread; -+ -+ /* -+ * Figure out how much to read -+ * -+ * If we are reading from the middle of a page then the most we -+ * can read is to the end of the page -+ */ -+ toread = len; -+ if (toread > (chip->device->page_size - column)) { -+ toread = chip->device->page_size - column; -+ } -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: buf=%p toread=%x row=%x column=%x last_row=%x\n", chip->name, buf, toread, row, column, chip->last_row); -+ -+ if (chip->last_row != row) { -+ /* -+ * Check if the block is bad -+ */ -+ if (test_bit(NAND_SPI_ER_BLOCK_FROM_ROW(row), chip->bbt)) { -+ mutex_unlock(&chip->lock); -+ return -EBADMSG; -+ } -+ -+ /* -+ * Load the appropriate page -+ */ -+ txbuf[0] = 0x13; -+ txbuf[1] = 0x00; -+ txbuf[2] = row >> 8; -+ txbuf[3] = row & 0xFF; -+ res = spi_write(spi, txbuf, 4); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed page load res=%d\n", chip->name, res); -+ mutex_unlock(&chip->lock); -+ return res; -+ } -+ -+ /* -+ * Wait -+ */ -+ res = nand_spi_er_busywait(chip, &stat); -+ if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); -+ if (res) { -+ mutex_unlock(&chip->lock); -+ return res; -+ } -+ -+ /* -+ * Chip is stuck? -+ */ -+ mutex_unlock(&chip->lock); -+ return -EIO; -+ } -+ -+ /* -+ * Check the ECC bits -+ */ -+ stat >>= 4; -+ if (stat == 1) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: ECC recovered, row=%x\n", chip->name, row); -+ retval = -EUCLEAN; -+ } -+ if (stat == 2) { -+ DEBUG(MTD_DEBUG_LEVEL0, "%s: failed ECC, row=%x\n", chip->name, row); -+ chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; -+ mutex_unlock(&chip->lock); -+ return -EBADMSG; -+ } -+ -+ } -+ -+ chip->last_row = row; -+ -+ /* -+ * Read out the data -+ */ -+ spi_message_init(&message); -+ memset(x, 0, sizeof(x)); -+ -+ txbuf[0] = 0x03; -+ txbuf[1] = column >> 8; -+ txbuf[2] = column & 0xFF; -+ txbuf[3] = 0; -+ x[0].tx_buf = txbuf; -+ x[0].len = 4; -+ spi_message_add_tail(&x[0], &message); -+ -+ x[1].rx_buf = buf; -+ x[1].len = toread; -+ spi_message_add_tail(&x[1], &message); -+ -+ res = spi_sync(spi, &message); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed data read res=%d\n", chip->name, res); -+ mutex_unlock(&chip->lock); -+ return res; -+ } -+ buf += toread; -+ len -= toread; -+ *retlen += toread; -+ -+ /* -+ * For the next page, increment the row and always start at column 0 -+ */ -+ column = 0; -+ row++; -+ } -+ -+ mutex_unlock(&chip->lock); -+ return retval; -+} -+ -+/* -+ * nand_spi_er_write -+ */ -+#define NOT_ALIGNED(x) ((x & (device->write_size - 1)) != 0) -+static int nand_spi_er_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ struct nand_spi_er *chip = mtd->priv; -+ struct spi_device *spi = chip->spi; -+ const struct nand_spi_er_device *device = chip->device; -+ uint32_t row; -+ uint32_t col; -+ uint8_t txbuf[4]; -+ int res; -+ size_t towrite; -+ -+ DEBUG(MTD_DEBUG_LEVEL2, "%s: write block to %llx len %d from %p\n", chip->name, to, len, buf); -+ -+ *retlen = 0; -+ -+ /* -+ * nothing to write -+ */ -+ if (!len) { -+ return 0; -+ } -+ -+ /* -+ * Reject writes which go over the end of the flash -+ */ -+ if ((to + len) > mtd->size) { -+ return -EINVAL; -+ } -+ -+ /* -+ * Check to see if everything is page aligned -+ */ -+ if (NOT_ALIGNED(to) || NOT_ALIGNED(len)) { -+ printk(KERN_NOTICE "nand_spi_er_write: Attempt to write non page aligned data\n"); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&chip->lock); -+ chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; -+ -+ /* -+ * If the first write is a partial write then write at most the number of -+ * bytes to get us page aligned and then the remainder will be -+ * page aligned. The last bit may be a partial page as well. -+ */ -+ col = to & (device->page_size - 1); -+ towrite = device->page_size - col; -+ if (towrite > len) { -+ towrite = len; -+ } -+ -+ /* -+ * Write the data -+ */ -+ row = to >> 11; -+ while (len) { -+ struct spi_message message; -+ struct spi_transfer x[2]; -+ uint8_t stat; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: write %p to row:%x col:%x len:%x rem:%x\n", chip->name, buf, row, col, towrite, len); -+ -+ /* -+ * Write enable -+ */ -+ txbuf[0] = 0x06; -+ res = spi_write(spi, txbuf, 1); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res); -+ mutex_unlock(&chip->lock); -+ return res; -+ } -+ -+ /* -+ * Write the data into the cache -+ */ -+ spi_message_init(&message); -+ memset(x, 0, sizeof(x)); -+ txbuf[0] = 0x02; -+ txbuf[1] = col >> 8; -+ txbuf[2] = col & 0xFF; -+ x[0].tx_buf = txbuf; -+ x[0].len = 3; -+ spi_message_add_tail(&x[0], &message); -+ x[1].tx_buf = buf; -+ x[1].len = towrite; -+ spi_message_add_tail(&x[1], &message); -+ res = spi_sync(spi, &message); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed cache write res=%d\n", chip->name, res); -+ goto done; -+ } -+ -+ /* -+ * Program execute -+ */ -+ txbuf[0] = 0x10; -+ txbuf[1] = 0x00; -+ txbuf[2] = row >> 8; -+ txbuf[3] = row & 0xFF; -+ res = spi_write(spi, txbuf, 4); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed prog execute res=%d\n", chip->name, res); -+ goto done; -+ } -+ -+ /* -+ * Wait -+ */ -+ res = nand_spi_er_busywait(chip, &stat); -+ if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); -+ if (res) { -+ goto done; -+ } -+ -+ /* -+ * Chip is stuck? -+ */ -+ res = -EIO; -+ goto done; -+ } -+ -+ if (stat & (1 << 3)) { -+ res = -EBADMSG; -+ goto done; -+ } -+ -+ row++; -+ buf += towrite; -+ len -= towrite; -+ *retlen += towrite; -+ -+ /* -+ * At this point, we are always page aligned so start at column 0. -+ * Note we may not have a full page to write at the end, hence the -+ * check if towrite > len. -+ */ -+ col = 0; -+ towrite = device->page_size; -+ if (towrite > len) { -+ towrite = len; -+ } -+ } -+ -+ mutex_unlock(&chip->lock); -+ return res; -+ -+done: -+ /* -+ * Write disable -+ */ -+ txbuf[0] = 0x04; -+ res = spi_write(spi, txbuf, 1); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res); -+ } -+ -+ mutex_unlock(&chip->lock); -+ -+ return res; -+} -+ -+/* -+ * nand_spi_er_isbad -+ */ -+static int nand_spi_er_isbad(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct nand_spi_er *chip = mtd->priv; -+ uint32_t block; -+ -+ if (ofs & (chip->device->erase_size - 1)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs); -+ return -EINVAL; -+ } -+ -+ block = ofs >> 17; -+ -+ return test_bit(block, chip->bbt); -+} -+ -+/* -+ * nand_spi_er_markbad -+ */ -+static int nand_spi_er_markbad(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct nand_spi_er *chip = mtd->priv; -+ struct spi_device *spi = chip->spi; -+ uint32_t block; -+ uint32_t row; -+ uint8_t txbuf[7]; -+ int res; -+ uint8_t stat; -+ -+ if (ofs & (chip->device->erase_size - 1)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs); -+ return -EINVAL; -+ } -+ -+ block = ofs >> 17; -+ -+ /* -+ * If it's already marked bad, no need to mark it -+ */ -+ if (test_bit(block, chip->bbt)) { -+ return 0; -+ } -+ -+ /* -+ * Mark it in our cache -+ */ -+ __set_bit(block, chip->bbt); -+ -+ /* -+ * Write the user bad block mark. If it fails, then we really -+ * can't do anything about it. -+ */ -+ mutex_lock(&chip->lock); -+ chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; -+ -+ /* -+ * Write enable -+ */ -+ txbuf[0] = 0x06; -+ res = spi_write(spi, txbuf, 1); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res); -+ mutex_unlock(&chip->lock); -+ return res; -+ } -+ -+ /* -+ * Write the mark -+ */ -+ txbuf[0] = 0x84; -+ txbuf[1] = 0x08; -+ txbuf[2] = NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET; -+ txbuf[3] = 0xde; -+ txbuf[4] = 0xad; -+ txbuf[5] = 0xbe; -+ txbuf[6] = 0xef; -+ res = spi_write(spi, txbuf, 7); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write mark res=%d\n", chip->name, res); -+ goto done; -+ } -+ -+ /* -+ * Program execute -+ */ -+ row = ofs >> 11; -+ txbuf[0] = 0x10; -+ txbuf[1] = 0x00; -+ txbuf[2] = row >> 8; -+ txbuf[3] = row & 0xFF; -+ res = spi_write(spi, txbuf, 4); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed program execute res=%d\n", chip->name, res); -+ goto done; -+ } -+ -+ /* -+ * Wait -+ */ -+ res = nand_spi_er_busywait(chip, &stat); -+ if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); -+ if (res) { -+ goto done; -+ } -+ -+ /* -+ * Chip is stuck? -+ */ -+ res = -EIO; -+ goto done; -+ } -+ -+ if (stat & (1 << 3)) { -+ res = -EBADMSG; -+ } -+ -+done: -+ /* -+ * Write disable -+ */ -+ txbuf[0] = 0x04; -+ res = spi_write(spi, txbuf, 1); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res); -+ } -+ -+ mutex_unlock(&chip->lock); -+ -+ return res; -+} -+ -+/* -+ * nand_spi_er_read_bbt -+ */ -+static int nand_spi_er_read_bbt(struct nand_spi_er *chip) -+{ -+ int j; -+ for (j = 0; j < chip->device->blocks; j++) { -+ uint8_t txbuf[4]; -+ uint8_t rxbuf[16]; -+ uint32_t bbmark; -+ int res; -+ unsigned short row = j << 6; -+ uint8_t stat; -+ -+ /* -+ * Read Page -+ */ -+ txbuf[0] = 0x13; -+ txbuf[1] = 0x00; -+ txbuf[2] = row >> 8; -+ txbuf[3] = row & 0xFF; -+ res = spi_write(chip->spi, txbuf, 4); -+ if (res) { -+ return res; -+ } -+ -+ /* -+ * Wait -+ */ -+ res = nand_spi_er_busywait(chip, &stat); -+ if (res || (stat & NAND_SPI_ER_STATUS_OIP)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat); -+ if (res) { -+ return res; -+ } -+ -+ /* -+ * Chip is stuck? -+ */ -+ return -EIO; -+ } -+ -+ /* -+ * Check factory bad block mark -+ */ -+ txbuf[0] = 0x03; -+ txbuf[1] = 0x08; -+ txbuf[2] = 0x00; -+ txbuf[3] = 0x00; -+ res = spi_write_then_read(chip->spi, txbuf, 4, rxbuf, 16); -+ if (res) { -+ return res; -+ } -+ if (rxbuf[0] != 0xFF) { -+ chip->nbb++; -+ __set_bit(j, chip->bbt); -+ continue; -+ } -+ -+ memcpy(&bbmark, &rxbuf[8], 4); -+ if (bbmark == 0xdeadbeef) { -+ chip->nbb++; -+ __set_bit(j, chip->bbt); -+ } -+ } -+ -+#if defined(CONFIG_MTD_DEBUG) && (MTD_DEBUG_LEVEL3 <= CONFIG_MTD_DEBUG_VERBOSE) -+ printk("%s: Bad Block Table:", chip->name); -+ for (j = 0; j < chip->device->blocks; j++) { -+ if ((j % 64) == 0) { -+ printk("\n%s: block %03x: ", chip->name, j); -+ } -+ printk("%c", test_bit(j, chip->bbt) ? 'X' : '.'); -+ } -+ printk("\n%s: Bad Block Numbers: ", chip->name); -+ for (j = 0; j < chip->device->blocks; j++) { -+ if (test_bit(j, chip->bbt)) { -+ printk("%x ", j); -+ } -+ } -+ printk("\n"); -+#endif -+ -+ return 0; -+} -+ -+#ifndef MODULE -+/* -+ * Called at boot time: -+ * -+ * nand_spi_er=read_only -+ * if read_only specified then do not unlock device -+ */ -+static int __init nand_spi_er_setup(char *str) -+{ -+ if (str && (strncasecmp(str, "read_only", 9) == 0)) { -+ read_only = 1; -+ } -+ return 0; -+} -+ -+__setup("nand_spi_er=", nand_spi_er_setup); -+#endif -+ -+/* -+ * nand_spi_er_probe -+ * Detect and initialize nand_spi_er device. -+ */ -+static int __devinit nand_spi_er_probe(struct spi_device *spi) -+{ -+ uint8_t txbuf[3]; -+ uint8_t rxbuf[2]; -+ int i; -+ int res; -+ size_t bbt_bytes; -+ struct nand_spi_er *chip; -+ const struct nand_spi_er_device *device; -+ -+ res = spi_setup(spi); -+ if (res) { -+ return res; -+ } -+ -+ /* -+ * Reset -+ */ -+ for (i = 0; i < 2; i++) { -+ txbuf[0] = 0xFF; -+ res = spi_write(spi, txbuf, 1); -+ if (res) { -+ return res; -+ } -+ udelay(250); -+ } -+ udelay(1000); -+ -+ /* -+ * Read ID -+ */ -+ txbuf[0] = 0x9F; -+ txbuf[1] = 0x00; -+ res = spi_write_then_read(spi, txbuf, 2, rxbuf, 2); -+ if (res) { -+ return res; -+ } -+ -+ device = nand_spi_er_devices; -+ for (i = 0; i < ARRAY_SIZE(nand_spi_er_devices); i++) { -+ if ((device->id0 == rxbuf[0]) && (device->id1 == rxbuf[1])) { -+ break; -+ } -+ device++; -+ } -+ if (i == ARRAY_SIZE(nand_spi_er_devices)) { -+ return -ENODEV; -+ } -+ -+ /* -+ * Initialize our chip structure -+ */ -+ bbt_bytes = DIV_ROUND_UP(device->blocks, BITS_PER_BYTE); -+ chip = kzalloc(sizeof(struct nand_spi_er) + bbt_bytes, GFP_KERNEL); -+ if (!chip) { -+ return -ENOMEM; -+ } -+ snprintf(chip->name, sizeof(chip->name), "%s.%d.%d", device->name, spi->master->bus_num, spi->chip_select); -+ -+ chip->spi = spi; -+ chip->device = device; -+ chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID; -+ -+ mutex_init(&chip->lock); -+ -+ chip->mtd.type = MTD_NANDFLASH; -+ chip->mtd.flags = MTD_WRITEABLE; -+ -+ /* -+ * #blocks * block size * n blocks -+ */ -+ chip->mtd.size = device->blocks * device->pages_per_block * device->page_size; -+ chip->mtd.erasesize = device->erase_size; -+ -+ /* -+ * 1 page, optionally we can support partial write (512) -+ */ -+ chip->mtd.writesize = device->write_size; -+ chip->mtd.name = device->name; -+ chip->mtd.erase = nand_spi_er_erase; -+ chip->mtd.read = nand_spi_er_read; -+ chip->mtd.write = nand_spi_er_write; -+ chip->mtd.block_isbad = nand_spi_er_isbad; -+ chip->mtd.block_markbad = nand_spi_er_markbad; -+ chip->mtd.priv = chip; -+ -+ /* -+ * Cache the bad block table -+ */ -+ res = nand_spi_er_read_bbt(chip); -+ if (res) { -+ kfree(chip); -+ return res; -+ } -+ -+ /* -+ * Un/lock the chip -+ */ -+ txbuf[0] = 0x1F; -+ txbuf[1] = 0xA0; -+ if (read_only) { -+ txbuf[2] = 0x38; -+ } else { -+ txbuf[2] = 0x00; -+ } -+ res = spi_write(spi, txbuf, 3); -+ if (res) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: failed lock operation res=%d\n", chip->name, res); -+ mutex_unlock(&chip->lock); -+ return res; -+ } -+ -+ spi_set_drvdata(spi, chip); -+ -+ printk(KERN_INFO "%s: added device %s size: %u KBytes %u bad blocks %s\n", spi->dev.bus_id, chip->mtd.name, DIV_ROUND_UP(chip->mtd.size, 1024), chip->nbb, read_only ? "[read only]" : ""); -+ return add_mtd_device(&chip->mtd); -+} -+ -+/* -+ * nand_spi_er_remove -+ */ -+static int __devexit nand_spi_er_remove(struct spi_device *spi) -+{ -+ struct nand_spi_er *chip = spi_get_drvdata(spi); -+ int status = 0; -+ -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", spi->dev.bus_id); -+ status = del_mtd_device(&chip->mtd); -+ if (status == 0) -+ kfree(chip); -+ return status; -+} -+ -+static struct spi_driver nand_spi_er_driver = { -+ .driver = { -+ .name = "nand-spi-er", -+ .bus = &spi_bus_type, -+ .owner = THIS_MODULE, -+ }, -+ -+ .probe = nand_spi_er_probe, -+ .remove = __devexit_p(nand_spi_er_remove), -+ -+ /* FIXME: investigate suspend and resume... */ -+}; -+ -+/* -+ * nand_spi_er_init -+ */ -+static int __init nand_spi_er_init(void) -+{ -+ return spi_register_driver(&nand_spi_er_driver); -+} -+module_init(nand_spi_er_init); -+ -+/* -+ * nand_spi_er_exit -+ */ -+static void __exit nand_spi_er_exit(void) -+{ -+ spi_unregister_driver(&nand_spi_er_driver); -+} -+module_exit(nand_spi_er_exit); -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Patrick Tjin"); -+MODULE_DESCRIPTION("MTD nand_spi_er driver"); -diff -ruN linux-2.6.30.10/drivers/mtd/devices/ubi32-m25p80.c linux-2.6.30.10-ubi/drivers/mtd/devices/ubi32-m25p80.c ---- linux-2.6.30.10/drivers/mtd/devices/ubi32-m25p80.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/mtd/devices/ubi32-m25p80.c 2009-12-11 11:45:16.000000000 +0200 -@@ -0,0 +1,1066 @@ -+/* -+ * drivers/mtd/devices/ubi32-m25p80.c -+ * NOR flash driver, Ubicom processor internal SPI flash interface. -+ * -+ * This code instantiates the serial flash that contains the -+ * original bootcode. The serial flash start at address 0x60000000 -+ * in both Ubicom32V3 and Ubicom32V4 ISAs. -+ * -+ * This piece of flash is made to appear as a Memory Technology -+ * Device (MTD) with this driver to allow Read/Write/Erase operations. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define UBICOM32_FLASH_BASE 0x60000000 -+#define UBICOM32_FLASH_MAX_SIZE 0x01000000 -+#define UBICOM32_FLASH_START 0x00000000 -+#define UBICOM32_KERNEL_OFFSET 0x00010000 /* The kernel starts after Ubicom -+ * .protect section. */ -+ -+static struct mtd_partition ubicom32_flash_partitions[] = { -+ { -+ .name = "Bootloader", /* Protected Section -+ * Partition */ -+ .size = 0x10000, -+ .offset = UBICOM32_FLASH_START, -+// .mask_flags = MTD_WRITEABLE /* Mark Read-only */ -+ }, -+ { -+ .name = "Kernel", /* Kernel Partition. */ -+ .size = 0, /* this will be set up during -+ * probe stage. At that time we -+ * will know end of linux image -+ * in flash. */ -+ .offset = MTDPART_OFS_APPEND, /* Starts right after Protected -+ * section. */ -+// .mask_flags = MTD_WRITEABLE /* Mark Read-only */ -+ }, -+ { -+ .name = "Rest", /* Rest of the flash. */ -+ .size = 0x200000, /* Use up what remains in the -+ * flash. */ -+ .offset = MTDPART_OFS_NXTBLK, /* Starts right after Protected -+ * section. */ -+ } -+}; -+ -+static struct flash_platform_data ubicom32_flash_data = { -+ .name = "ubicom32_boot_flash", -+ .parts = ubicom32_flash_partitions, -+ .nr_parts = ARRAY_SIZE(ubicom32_flash_partitions), -+}; -+ -+static struct resource ubicom32_flash_resource[] = { -+ { -+ .start = UBICOM32_FLASH_BASE, -+ .end = UBICOM32_FLASH_BASE + -+ UBICOM32_FLASH_MAX_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+static struct platform_device ubicom32_flash_device = { -+ .name = "ubicom32flashdriver", -+ .id = 0, /* Bus number */ -+ .num_resources = ARRAY_SIZE(ubicom32_flash_resource), -+ .resource = ubicom32_flash_resource, -+ .dev = { -+ .platform_data = &ubicom32_flash_data, -+ }, -+}; -+ -+static struct platform_device *ubicom32_flash_devices[] = { -+ &ubicom32_flash_device, -+}; -+ -+static int __init ubicom32_flash_init(void) -+{ -+ printk(KERN_INFO "%s(): registering device resources\n", -+ __FUNCTION__); -+ platform_add_devices(ubicom32_flash_devices, -+ ARRAY_SIZE(ubicom32_flash_devices)); -+ return 0; -+} -+ -+arch_initcall(ubicom32_flash_init); -+ -+/* -+ * MTD SPI driver for ST M25Pxx (and similar) serial flash chips through -+ * Ubicom32 SPI controller. -+ * -+ * Author: Mike Lavender, mike@steroidmicros.com -+ * -+ * Copyright (c) 2005, Intec Automation Inc. -+ * -+ * Some parts are based on lart.c by Abraham Van Der Merwe -+ * -+ * Cleaned up and generalized based on mtd_dataflash.c -+ * -+ * This code is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#define FLASH_PAGESIZE 256 -+ -+/* Flash opcodes. */ -+#define OPCODE_WREN 0x06 /* Write enable */ -+#define OPCODE_RDSR 0x05 /* Read status register */ -+#define OPCODE_READ 0x03 /* Read data bytes (low frequency) */ -+#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ -+#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ -+#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ -+#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ -+#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ -+#define OPCODE_RDID 0x9f /* Read JEDEC ID */ -+ -+/* Status Register bits. */ -+#define SR_WIP 1 /* Write in progress */ -+#define SR_WEL 2 /* Write enable latch */ -+/* meaning of other SR_* bits may differ between vendors */ -+#define SR_BP0 4 /* Block protect 0 */ -+#define SR_BP1 8 /* Block protect 1 */ -+#define SR_BP2 0x10 /* Block protect 2 */ -+#define SR_SRWD 0x80 /* SR write protect */ -+ -+/* Define max times to check status register before we give up. */ -+#define MAX_READY_WAIT_COUNT 100000 -+ -+ -+#ifdef CONFIG_MTD_PARTITIONS -+#define mtd_has_partitions() (1) -+#else -+#define mtd_has_partitions() (0) -+#endif -+ -+/* -+ * Ubicom32 FLASH Command Set -+ */ -+#define FLASH_FC_INST_CMD 0x00 /* for SPI command only transaction */ -+#define FLASH_FC_INST_WR 0x01 /* for SPI write transaction */ -+#define FLASH_FC_INST_RD 0x02 /* for SPI read transaction */ -+ -+#define ALIGN_DOWN(v, a) ((v) & ~((a) - 1)) -+#define ALIGN_UP(v, a) (((v) + ((a) - 1)) & ~((a) - 1)) -+ -+#define FLASH_COMMAND_KICK_OFF(io) \ -+ asm volatile( \ -+ " bset "D(IO_INT_CLR)"(%0), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" \ -+ " jmpt.t .+4 \n\t" \ -+ " bset "D(IO_INT_SET)"(%0), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" \ -+ : \ -+ : "a" (io) \ -+ : "memory", "cc" \ -+ ); -+ -+#define FLASH_COMMAND_WAIT_FOR_COMPLETION(io) \ -+ asm volatile( \ -+ " btst "D(IO_INT_STATUS)"(%0), #%%bit("D(IO_XFL_INT_DONE)") \n\t" \ -+ " jmpeq.f .-4 \n\t" \ -+ : \ -+ : "a" (io) \ -+ : "memory", "cc" \ -+ ); -+ -+#define FLASH_COMMAND_EXEC(io) \ -+ FLASH_COMMAND_KICK_OFF(io) \ -+ FLASH_COMMAND_WAIT_FOR_COMPLETION(io) -+ -+ -+#define OSC1_FREQ 12000000 -+#define TEN_MICRO_SECONDS (OSC1_FREQ * 10 / 1000000) -+ -+/* -+ * We will have to eventually replace this null definition with the real thing. -+ */ -+#define WATCHDOG_RESET() -+ -+#define EXTFLASH_WRITE_FIFO_SIZE 32 -+#define EXTFLASH_WRITE_BLOCK_SIZE EXTFLASH_WRITE_FIFO_SIZE /* limit the size to -+ * FIFO capacity, so -+ * the thread can be -+ * suspended. */ -+ -+#define JFFS2_FILESYSTEM_SIZE 0x100000 -+ -+/****************************************************************************/ -+ -+struct m25p { -+ struct platform_device *plt_dev; -+ struct mutex lock; -+ struct mtd_info mtd; -+ unsigned partitioned:1; -+ u8 erase_opcode; -+ u8 command[4]; -+}; -+ -+static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) -+{ -+ return container_of(mtd, struct m25p, mtd); -+} -+ -+/****************************************************************************/ -+ -+/* -+ * Internal helper functions -+ */ -+ -+/* -+ * Read the status register, returning its value in the location -+ * Return the status register value. -+ * Returns negative if error occurred. -+ */ -+static int read_sr(struct m25p *flash) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; -+ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | -+ IO_XFL_CTL1_FC_DATA(1); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDSR); -+ FLASH_COMMAND_EXEC(io); -+ -+ return io->status1 & 0xff; -+} -+ -+/* -+ * mem_flash_io_read_u32() -+ */ -+static u32 mem_flash_io_read_u32(u32 addr) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | -+ IO_XFL_CTL1_FC_DATA(4) | IO_XFL_CTL1_FC_DUMMY(1) | -+ IO_XFL_CTL1_FC_ADDR; -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_FAST_READ) | -+ IO_XFL_CTL2_FC_ADDR(addr); -+ FLASH_COMMAND_EXEC(io); -+ return io->status1; -+} -+ -+/* -+ * mem_flash_read_u8() -+ */ -+static u8 mem_flash_read_u8(u32 addr) -+{ -+ u32 tmp_addr = ALIGN_DOWN(addr, 4); -+ u32 tmp_data = mem_flash_io_read_u32(tmp_addr); -+ u8 *ptr = (u8 *)&tmp_data; -+ return ptr[addr & 0x3]; -+} -+ -+/* -+ * mem_flash_read() -+ * No need to lock as read is implemented with ireads (same as normal flash -+ * execution). -+ */ -+static void mem_flash_read(u32 addr, void *dst, size_t length) -+{ -+ /* -+ * Range check -+ */ -+ /* -+ * Fix source alignment. -+ */ -+ while (addr & 0x03) { -+ if (length == 0) { -+ return; -+ } -+ *((u8 *)dst) = mem_flash_read_u8(addr++); -+ dst++; -+ length--; -+ } -+ -+ while (length >= 4) { -+ u32 tmp_data = mem_flash_io_read_u32(addr); -+ addr += 4; -+ length -= 4; -+ -+ /* -+ * Send the data to the destination. -+ */ -+ memcpy((void *)dst, (void *)&tmp_data, 4); -+ dst += 4; -+ } -+ -+ while (length--) { -+ *((u8 *)dst) = mem_flash_read_u8(addr++); -+ dst++; -+ } -+} -+ -+/* -+ * mem_flash_wait_until_complete() -+ */ -+static void mem_flash_wait_until_complete(void) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; -+ -+ do { -+ /* -+ * Put a delay here to deal with flash programming problem. -+ */ -+ u32 mptval = UBICOM32_IO_TIMER->mptval + TEN_MICRO_SECONDS; -+ while (UBICOM32_IO_TIMER->mptval < mptval) -+ ; -+ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | -+ IO_XFL_CTL1_FC_DATA(1); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDSR); -+ FLASH_COMMAND_EXEC(io); -+ } while (io->status1 & SR_WIP); -+} -+ -+/* -+ * mem_flash_write_next() -+ */ -+static size_t mem_flash_write_next(u32 addr, u8 *buf, size_t length) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; -+ u32 data_start = addr; -+ u32 data_end = addr + length; -+ size_t count; -+ u32 i, j; -+ -+ /* -+ * Top limit address. -+ */ -+ u32 block_start = ALIGN_DOWN(data_start, 4); -+ u32 block_end = block_start + EXTFLASH_WRITE_BLOCK_SIZE; -+ -+ union { -+ u8 byte[EXTFLASH_WRITE_BLOCK_SIZE]; -+ u32 word[EXTFLASH_WRITE_BLOCK_SIZE / 4]; -+ } write_buf; -+ -+ u32 *flash_addr = (u32 *)block_start; -+ -+ /* -+ * The write block must be limited by FLASH internal buffer. -+ */ -+ u32 block_end_align = ALIGN_DOWN(block_end, 256); -+ bool write_needed; -+ -+ block_end = (block_end_align > block_start) -+ ? block_end_align : block_end; -+ data_end = (data_end <= block_end) ? data_end : block_end; -+ block_end = ALIGN_UP(data_end, 4); -+ count = data_end - data_start; -+ -+ /* -+ * Transfer data to a buffer. -+ */ -+ for (i = 0; i < (block_end - block_start) / 4; i++) { -+ /* -+ * The FLASH read can hold D-cache for a long time. -+ * Use I/O operation to read FLASH to avoid starving other -+ * threads, especially HRT. (Do this for application only) -+ */ -+ write_buf.word[i] = mem_flash_io_read_u32( -+ (u32)(&flash_addr[i])); -+ } -+ -+ write_needed = false; -+ for (i = 0, j = (data_start - block_start); -+ i < (data_end - data_start); i++, j++) { -+ write_needed = write_needed || (write_buf.byte[j] != buf[i]); -+ write_buf.byte[j] &= buf[i]; -+ } -+ -+ -+ /* -+ * If the data in FLASH is identical to what to be written. Then skip -+ * it. -+ */ -+ if (write_needed) { -+ /* -+ * Write to flash. -+ */ -+ void *tmp __attribute__((unused)); -+ s32 extra_words; -+ -+ asm volatile( -+ " move.4 %0, %2 \n\t" -+ " bset "D(IO_INT_SET)"(%1), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)") \n\t" -+ " pipe_flush 0 \n\t" -+ " .rept "D(EXTFLASH_WRITE_FIFO_SIZE / 4)" \n\t" -+ " move.4 "D(IO_TX_FIFO)"(%1), (%0)4++ \n\t" -+ " .endr \n\t" -+ : "=&a" (tmp) -+ : "a" (io), "r" (&write_buf.word[0]) -+ : "memory", "cc" -+ ); -+ -+ /* Lock FLASH for write access. */ -+ io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; -+ -+ /* Command: WREN */ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_WREN); -+ FLASH_COMMAND_EXEC(io); -+ -+ /* Command: BYTE PROGRAM */ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | -+ IO_XFL_CTL1_FC_DATA(block_end - block_start) | -+ IO_XFL_CTL1_FC_ADDR; -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_PP) | -+ IO_XFL_CTL2_FC_ADDR(block_start); -+ FLASH_COMMAND_KICK_OFF(io); -+ -+ extra_words = (s32)(block_end - block_start - -+ EXTFLASH_WRITE_FIFO_SIZE) / 4; -+ if (extra_words > 0) { -+ asm volatile( -+ " move.4 %0, %3 \n\t" -+ "1: cmpi "D(IO_FIFO_LEVEL)"(%1), #4 \n\t" -+ " jmpgt.s.t 1b \n\t" -+ " move.4 "D(IO_TX_FIFO)"(%1), (%0)4++ \n\t" -+ " add.4 %2, #-1, %2 \n\t" -+ " jmpgt.t 1b \n\t" -+ : "=&a" (tmp) -+ : "a" (io), "d" (extra_words), -+ "r" (&write_buf.word[EXTFLASH_WRITE_FIFO_SIZE / 4]) -+ : "memory", "cc" -+ ); -+ } -+ FLASH_COMMAND_WAIT_FOR_COMPLETION(io); -+ -+ mem_flash_wait_until_complete(); -+ -+ -+ /* Unlock FLASH for cache access. */ -+ io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; -+ } -+ -+ /* -+ * Complete. -+ */ -+ return count; -+} -+ -+/* -+ * mem_flash_write() -+ */ -+static void mem_flash_write(u32 addr, const void *src, size_t length) -+{ -+ /* -+ * Write data -+ */ -+ u8_t *ptr = (u8_t *)src; -+ while (length) { -+ size_t count = mem_flash_write_next(addr, ptr, length); -+ addr += count; -+ ptr += count; -+ length -= count; -+ } -+} -+ -+/* -+ * Service routine to read status register until ready, or timeout occurs. -+ * Returns non-zero if error. -+ */ -+static int wait_till_ready(struct m25p *flash) -+{ -+ int count; -+ int sr; -+ -+ /* one chip guarantees max 5 msec wait here after page writes, -+ * but potentially three seconds (!) after page erase. -+ */ -+ for (count = 0; count < MAX_READY_WAIT_COUNT; count++) { -+ u32 mptval; -+ sr = read_sr(flash); -+ if (sr < 0) -+ break; -+ else if (!(sr & SR_WIP)) -+ return 0; -+ -+ /* -+ * Put a 10us delay here to deal with flash programming problem. -+ */ -+ mptval = UBICOM32_IO_TIMER->mptval + TEN_MICRO_SECONDS; -+ while ((s32)(mptval - UBICOM32_IO_TIMER->mptval) > 0) { -+ WATCHDOG_RESET(); -+ } -+ /* REVISIT sometimes sleeping would be best */ -+ } -+ -+ return 1; -+} -+ -+/* -+ * mem_flash_erase_page() -+ */ -+static void mem_flash_erase_page(u32 addr) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; -+ -+ /* Lock FLASH for write access. */ -+ io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; -+ -+ /* Command: WREN */ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_WREN); -+ FLASH_COMMAND_EXEC(io); -+ -+ /* Command: ERASE */ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD) | -+ IO_XFL_CTL1_FC_ADDR; -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_SE) | -+ IO_XFL_CTL2_FC_ADDR(addr); -+ FLASH_COMMAND_EXEC(io); -+ -+ mem_flash_wait_until_complete(); -+ -+ /* Unlock FLASH for cache access. */ -+ io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; -+} -+ -+/* -+ * mem_flash_erase() -+ */ -+static u32 mem_flash_erase(u32 addr, u32 length) -+{ -+ /* -+ * Calculate the endaddress to be the first address of the page -+ * just beyond this erase section of pages. -+ */ -+ u32 endaddr = addr + length; -+ -+ /* -+ * Erase. -+ */ -+ while (addr < endaddr) { -+ u32 test_addr = addr; -+ mem_flash_erase_page(addr); -+ -+ /* -+ * Test how much was erased as actual flash page at this address -+ * may be smaller than the expected page size. -+ */ -+ while (test_addr < endaddr) { -+ /* -+ * The FLASH read can hold D-cache for a long time. Use -+ * I/O operation to read FLASH to avoid starving other -+ * threads, especially HRT. (Do this for application -+ * only) -+ */ -+ if (mem_flash_io_read_u32(test_addr) != 0xFFFFFFFF) { -+ break; -+ } -+ test_addr += 4; -+ } -+ if (test_addr == addr) { -+ printk("erase failed at address 0x%x, skipping", -+ test_addr); -+ test_addr += 4; -+ return 1; -+ } -+ addr = test_addr; -+ } -+ return 0; -+} -+ -+ -+/****************************************************************************/ -+ -+/* -+ * MTD implementation -+ */ -+ -+/* -+ * Erase an address range on the flash chip. The address range may extend -+ * one or more erase sectors. Return an error is there is a problem erasing. -+ */ -+static int ubicom32_flash_driver_erase(struct mtd_info *mtd, -+ struct erase_info *instr) -+{ -+ struct m25p *flash = mtd_to_m25p(mtd); -+ u32 addr, len; -+ -+ DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %lld\n", -+ dev_name(&flash->plt_dev->dev), __FUNCTION__, "at", -+ (u32)instr->addr, instr->len); -+ -+ /* sanity checks */ -+ if (instr->addr + instr->len > flash->mtd.size) -+ return -EINVAL; -+ if ((instr->addr % mtd->erasesize) != 0 -+ || (instr->len % mtd->erasesize) != 0) { -+ return -EINVAL; -+ } -+ -+ addr = instr->addr + UBICOM32_FLASH_BASE; -+ len = instr->len; -+ -+ mutex_lock(&flash->lock); -+ -+ /* REVISIT in some cases we could speed up erasing large regions -+ * by using OPCODE_SE instead of OPCODE_BE_4K -+ */ -+ -+ /* now erase those sectors */ -+ if (mem_flash_erase(addr, len)) { -+ instr->state = MTD_ERASE_FAILED; -+ mutex_unlock(&flash->lock); -+ return -EIO; -+ } -+ -+ mutex_unlock(&flash->lock); -+ instr->state = MTD_ERASE_DONE; -+ mtd_erase_callback(instr); -+ return 0; -+} -+ -+/* -+ * Read an address range from the flash chip. The address range -+ * may be any size provided it is within the physical boundaries. -+ */ -+static int ubicom32_flash_driver_read(struct mtd_info *mtd, loff_t from, -+ size_t len, size_t *retlen, u_char *buf) -+{ -+ struct m25p *flash = mtd_to_m25p(mtd); -+ u32 base_addr = UBICOM32_FLASH_BASE + from; -+ -+ DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", -+ dev_name(&flash->plt_dev->dev), __FUNCTION__, "from", -+ (u32)from, len); -+ -+ /* sanity checks */ -+ if (!len) -+ return 0; -+ -+ if (from + len > flash->mtd.size) -+ return -EINVAL; -+ -+ /* Byte count starts at zero. */ -+ if (retlen) -+ *retlen = 0; -+ -+ mutex_lock(&flash->lock); -+ -+ /* Wait till previous write/erase is done. */ -+ if (wait_till_ready(flash)) { -+ /* REVISIT status return?? */ -+ mutex_unlock(&flash->lock); -+ return 1; -+ } -+ -+ mem_flash_read(base_addr, (void *)buf, len); -+ -+ if (retlen) -+ *retlen = len; -+ -+ mutex_unlock(&flash->lock); -+ -+ return 0; -+} -+ -+/* -+ * Write an address range to the flash chip. Data must be written in -+ * FLASH_PAGESIZE chunks. The address range may be any size provided -+ * it is within the physical boundaries. -+ */ -+static int ubicom32_flash_driver_write(struct mtd_info *mtd, loff_t to, -+ size_t len, size_t *retlen, -+ const u_char *buf) -+{ -+ struct m25p *flash = mtd_to_m25p(mtd); -+ u32 base_addr = UBICOM32_FLASH_BASE + to; -+ DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", -+ dev_name(&flash->plt_dev->dev), __FUNCTION__, "to", -+ (u32)to, len); -+ -+ if (retlen) -+ *retlen = 0; -+ -+ /* sanity checks */ -+ if (!len) -+ return 0; -+ -+ if (to + len > flash->mtd.size) -+ return -EINVAL; -+ -+ mutex_lock(&flash->lock); -+ -+ mem_flash_write(base_addr, (void *) buf, len); -+ -+ /* Wait until finished previous write command. */ -+ if (wait_till_ready(flash)) { -+ mutex_unlock(&flash->lock); -+ return 1; -+ } -+ -+ if (retlen) -+ *retlen = len; -+ -+ mutex_unlock(&flash->lock); -+ return 0; -+} -+ -+ -+/****************************************************************************/ -+ -+/* -+ * SPI device driver setup and teardown -+ */ -+ -+struct flash_info { -+ char *name; -+ -+ /* JEDEC id zero means "no ID" (most older chips); otherwise it has -+ * a high byte of zero plus three data bytes: the manufacturer id, -+ * then a two byte device id. -+ */ -+ u32 jedec_id; -+ -+ /* The size listed here is what works with OPCODE_SE, which isn't -+ * necessarily called a "sector" by the vendor. -+ */ -+ unsigned sector_size; -+ u16 n_sectors; -+ -+ u16 flags; -+#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ -+}; -+ -+ -+/* NOTE: double check command sets and memory organization when you add -+ * more flash chips. This current list focusses on newer chips, which -+ * have been converging on command sets which including JEDEC ID. -+ */ -+static struct flash_info __devinitdata m25p_data[] = { -+ -+ /* Atmel -- some are (confusingly) marketed as "DataFlash" */ -+ { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, }, -+ { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, -+ -+ { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, -+ -+ { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, -+ { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, -+ { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, }, -+ { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, }, -+ -+ /* Spansion -- single (large) sector size only, at least -+ * for the chips listed here (without boot sectors). -+ */ -+ { "s25sl004a", 0x010212, 64 * 1024, 8, }, -+ { "s25sl008a", 0x010213, 64 * 1024, 16, }, -+ { "s25sl016a", 0x010214, 64 * 1024, 32, }, -+ { "s25sl032a", 0x010215, 64 * 1024, 64, }, -+ { "s25sl064a", 0x010216, 64 * 1024, 128, }, -+ -+ /* SST -- large erase sizes are "overlays", "sectors" are 4K */ -+ { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, }, -+ { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, }, -+ { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, }, -+ { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, }, -+ -+ /* ST Microelectronics -- newer production may have feature updates */ -+ { "m25p05", 0x202010, 32 * 1024, 2, }, -+ { "m25p10", 0x202011, 32 * 1024, 4, }, -+ { "m25p20", 0x202012, 64 * 1024, 4, }, -+ { "m25p40", 0x202013, 64 * 1024, 8, }, -+ { "m25p80", 0, 64 * 1024, 16, }, -+ { "m25p16", 0x202015, 64 * 1024, 32, }, -+ { "m25p32", 0x202016, 64 * 1024, 64, }, -+ { "m25p64", 0x202017, 64 * 1024, 128, }, -+ { "m25p128", 0x202018, 256 * 1024, 64, }, -+ -+ { "m45pe80", 0x204014, 64 * 1024, 16, }, -+ { "m45pe16", 0x204015, 64 * 1024, 32, }, -+ -+ { "m25pe80", 0x208014, 64 * 1024, 16, }, -+ { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, }, -+ -+ /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ -+ { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, }, -+ { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, }, -+ { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, }, -+ { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, }, -+ { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, }, -+ { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, }, -+ { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, }, -+ -+ /* Macronix -- mx25lxxx */ -+ { "mx25l32", 0xc22016, 64 * 1024, 64, }, -+ { "mx25l64", 0xc22017, 64 * 1024, 128, }, -+ { "mx25l128", 0xc22018, 64 * 1024, 256, }, -+ -+}; -+ -+struct flash_info *__devinit jedec_probe(struct platform_device *spi) -+{ -+ int tmp; -+ u32 jedec; -+ struct flash_info *info; -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA; -+ -+ /* -+ * Setup and run RDID command on the flash. -+ */ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | -+ IO_XFL_CTL1_FC_DATA(3); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDID); -+ FLASH_COMMAND_EXEC(io); -+ -+ jedec = io->status1 & 0x00ffffff; -+ -+ for (tmp = 0, info = m25p_data; -+ tmp < ARRAY_SIZE(m25p_data); -+ tmp++, info++) { -+ if (info->jedec_id == jedec) -+ return info; -+ } -+ dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); -+ return NULL; -+} -+ -+ -+/* -+ * board specific setup should have ensured the SPI clock used here -+ * matches what the READ command supports, at least until this driver -+ * understands FAST_READ (for clocks over 25 MHz). -+ */ -+static int __devinit ubicom32_flash_probe(struct platform_device *spi) -+{ -+ struct flash_platform_data *data; -+ struct m25p *flash; -+ struct flash_info *info; -+ unsigned i; -+ -+ /* Platform data helps sort out which chip type we have, as -+ * well as how this board partitions it. If we don't have -+ * a chip ID, try the JEDEC id commands; they'll work for most -+ * newer chips, even if we don't recognize the particular chip. -+ */ -+ data = spi->dev.platform_data; -+ if (data && data->type) { -+ for (i = 0, info = m25p_data; -+ i < ARRAY_SIZE(m25p_data); -+ i++, info++) { -+ if (strcmp(data->type, info->name) == 0) -+ break; -+ } -+ -+ /* unrecognized chip? */ -+ if (i == ARRAY_SIZE(m25p_data)) { -+ DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n", -+ dev_name(&spi->dev), data->type); -+ info = NULL; -+ -+ /* recognized; is that chip really what's there? */ -+ } else if (info->jedec_id) { -+ struct flash_info *chip = jedec_probe(spi); -+ -+ if (!chip || chip != info) { -+ dev_warn(&spi->dev, "found %s, expected %s\n", -+ chip ? chip->name : "UNKNOWN", -+ info->name); -+ info = NULL; -+ } -+ } -+ } else -+ info = jedec_probe(spi); -+ -+ if (!info) -+ return -ENODEV; -+ -+ flash = kzalloc(sizeof *flash, GFP_KERNEL); -+ if (!flash) -+ return -ENOMEM; -+ -+ flash->plt_dev = spi; -+ mutex_init(&flash->lock); -+ dev_set_drvdata(&spi->dev, flash); -+ -+ if (data && data->name) -+ flash->mtd.name = data->name; -+ else -+ flash->mtd.name = dev_name(&spi->dev); -+ -+ flash->mtd.type = MTD_NORFLASH; -+ flash->mtd.writesize = 1; -+ flash->mtd.flags = MTD_CAP_NORFLASH; -+ flash->mtd.size = info->sector_size * info->n_sectors; -+ flash->mtd.erase = ubicom32_flash_driver_erase; -+ flash->mtd.read = ubicom32_flash_driver_read; -+ flash->mtd.write = ubicom32_flash_driver_write; -+ -+ /* prefer "small sector" erase if possible */ -+ /* -+ * The Ubicom erase code does not use the opcode for smaller sectors, -+ * so disable that functionality and keep erasesize == sector_size -+ * so that the test in ubicom32_flash_driver_erase works properly. -+ * -+ * This was: `if (info->flags & SECT_4K) {' instead of `if (0) {' -+ */ -+ if (0) { -+ flash->erase_opcode = OPCODE_BE_4K; -+ flash->mtd.erasesize = 4096; -+ } else { -+ flash->erase_opcode = OPCODE_SE; -+ flash->mtd.erasesize = info->sector_size; -+ } -+ -+ dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name, -+ flash->mtd.size / 1024); -+ -+ DEBUG(MTD_DEBUG_LEVEL2, -+ "mtd .name = %s, .size = 0x%.8llx (%lluMiB) " -+ ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", -+ flash->mtd.name, -+ flash->mtd.size, flash->mtd.size / (1024*1024), -+ flash->mtd.erasesize, flash->mtd.erasesize / 1024, -+ flash->mtd.numeraseregions); -+ -+ if (flash->mtd.numeraseregions) -+ for (i = 0; i < flash->mtd.numeraseregions; i++) -+ DEBUG(MTD_DEBUG_LEVEL2, -+ "mtd.eraseregions[%d] = { .offset = 0x%.8llx, " -+ ".erasesize = 0x%.8x (%uKiB), " -+ ".numblocks = %d }\n", -+ i, flash->mtd.eraseregions[i].offset, -+ flash->mtd.eraseregions[i].erasesize, -+ flash->mtd.eraseregions[i].erasesize / 1024, -+ flash->mtd.eraseregions[i].numblocks); -+ -+ -+ /* partitions should match sector boundaries; and it may be good to -+ * use readonly partitions for writeprotected sectors (BP2..BP0). -+ */ -+ if (mtd_has_partitions()) { -+ struct mtd_partition *parts = NULL; -+ int nr_parts = 0; -+ -+#ifdef CONFIG_MTD_CMDLINE_PARTS -+ static const char *part_probes[] = { "cmdlinepart", NULL, }; -+ -+ nr_parts = parse_mtd_partitions(&flash->mtd, -+ part_probes, &parts, 0); -+#endif -+ -+ if (nr_parts <= 0 && data && data->parts) { -+ parts = data->parts; -+ nr_parts = data->nr_parts; -+ if (nr_parts >= 2) { -+ /* -+ * Set last partition size to be 1M. -+ */ -+ parts[1].size = flash->mtd.size - -+ parts[0].size - JFFS2_FILESYSTEM_SIZE; -+ parts[2].size = JFFS2_FILESYSTEM_SIZE; -+ } -+ } -+ -+ if (nr_parts > 0) { -+ for (i = 0; i < nr_parts; i++) { -+ DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " -+ "{.name = %s, .offset = 0x%.8llx, " -+ ".size = 0x%.8llx (%lluKiB) }\n", -+ i, parts[i].name, -+ parts[i].offset, -+ parts[i].size, -+ parts[i].size / 1024); -+ } -+ flash->partitioned = 1; -+ return add_mtd_partitions(&flash->mtd, parts, nr_parts); -+ } -+ } else if (data->nr_parts) -+ dev_warn(&spi->dev, "ignoring %d default partitions on %s\n", -+ data->nr_parts, data->name); -+ -+ return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0; -+} -+ -+ -+static int __devexit ubicom32_flash_remove(struct spi_device *spi) -+{ -+ struct m25p *flash = dev_get_drvdata(&spi->dev); -+ int status; -+ -+ /* Clean up MTD stuff. */ -+ if (mtd_has_partitions() && flash->partitioned) -+ status = del_mtd_partitions(&flash->mtd); -+ else -+ status = del_mtd_device(&flash->mtd); -+ if (status == 0) -+ kfree(flash); -+ return 0; -+} -+ -+static struct platform_driver ubicom32_flash_driver = { -+ .driver = { -+ .name = "ubicom32flashdriver", -+ .bus = &platform_bus_type, -+ .owner = THIS_MODULE, -+ }, -+ .probe = ubicom32_flash_probe, -+ .remove = NULL, -+}; -+ -+static int ubicom32_flash_driver_init(void) -+{ -+ return platform_driver_register(&ubicom32_flash_driver); -+} -+ -+ -+static void ubicom32_flash_driver_exit(void) -+{ -+ platform_driver_unregister(&ubicom32_flash_driver); -+} -+ -+ -+module_init(ubicom32_flash_driver_init); -+module_exit(ubicom32_flash_driver_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Mike Lavender"); -+MODULE_DESCRIPTION("Ubicom32 MTD SPI driver for ST M25Pxx flash chips"); -diff -ruN linux-2.6.30.10/drivers/mtd/devices/ubi32-nand-spi-er.c linux-2.6.30.10-ubi/drivers/mtd/devices/ubi32-nand-spi-er.c ---- linux-2.6.30.10/drivers/mtd/devices/ubi32-nand-spi-er.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/mtd/devices/ubi32-nand-spi-er.c 2009-12-11 11:45:16.000000000 +0200 -@@ -0,0 +1,1188 @@ -+/* -+ * Micron SPI-ER NAND Flash Memory -+ * This code uses the built in Ubicom flash controller -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+*/ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define DRIVER_NAME "ubi32-nand-spi-er" -+#define UBI32_NAND_SPI_ER_BLOCK_FROM_ROW(row) (row >> 6) -+ -+#define UBI32_NAND_SPI_ER_STATUS_P_FAIL (1 << 3) -+#define UBI32_NAND_SPI_ER_STATUS_E_FAIL (1 << 2) -+#define UBI32_NAND_SPI_ER_STATUS_OIP (1 << 0) -+ -+#define UBI32_NAND_SPI_ER_LAST_ROW_INVALID 0xFFFFFFFF -+#define UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET 0x08 -+ -+struct ubi32_nand_spi_er_device { -+ const char *name; -+ -+ uint16_t id; -+ -+ unsigned int blocks; -+ unsigned int pages_per_block; -+ unsigned int page_size; -+ unsigned int write_size; -+ unsigned int erase_size; -+}; -+ -+struct ubi32_nand_spi_er { -+ char name[24]; -+ -+ const struct ubi32_nand_spi_er_device *device; -+ -+ struct mutex lock; -+ struct platform_device *pdev; -+ -+ struct mtd_info mtd; -+ -+ unsigned int last_row; /* the last row we fetched */ -+ -+ /* -+ * Bad block table (MUST be last in strcuture) -+ */ -+ unsigned long nbb; -+ unsigned long bbt[0]; -+}; -+ -+/* -+ * Chip supports a write_size of 512, but we cannot do partial -+ * page with command 0x84. -+ * -+ * We need to use command 0x84 because we cannot fill the FIFO fast -+ * enough to transfer the whole 512 bytes at a time. (maybe through -+ * OCM?) -+ */ -+const struct ubi32_nand_spi_er_device ubi32_nand_spi_er_devices[] = { -+ { -+ name: "MT29F1G01ZDC", -+ id: 0x2C12, -+ blocks: 1024, -+ pages_per_block: 64, -+ page_size: 2048, -+ write_size: 2048, -+ erase_size: 64 * 2048, -+ }, -+ { -+ name: "MT29F1G01ZDC", -+ id: 0x2C13, -+ blocks: 1024, -+ pages_per_block: 64, -+ page_size: 2048, -+ write_size: 2048, -+ erase_size: 64 * 2048, -+ }, -+}; -+ -+static int read_only = 0; -+module_param(read_only, int, 0); -+MODULE_PARM_DESC(read_only, "Leave device locked"); -+ -+/* -+ * Ubicom32 FLASH Command Set -+ */ -+#define FLASH_PORT RA -+ -+#define FLASH_FC_INST_CMD 0x00 /* for SPI command only transaction */ -+#define FLASH_FC_INST_WR 0x01 /* for SPI write transaction */ -+#define FLASH_FC_INST_RD 0x02 /* for SPI read transaction */ -+ -+#define FLASH_COMMAND_KICK_OFF(io) \ -+ asm volatile( \ -+ " bset "D(IO_INT_CLR)"(%0), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" \ -+ " jmpt.t .+4 \n\t" \ -+ " bset "D(IO_INT_SET)"(%0), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" \ -+ : \ -+ : "a" (io) \ -+ : "cc" \ -+ ); -+ -+#define FLASH_COMMAND_WAIT_FOR_COMPLETION(io) \ -+ asm volatile( \ -+ " btst "D(IO_INT_STATUS)"(%0), #%%bit("D(IO_XFL_INT_DONE)") \n\t" \ -+ " jmpeq.f .-4 \n\t" \ -+ : \ -+ : "a" (io) \ -+ : "cc" \ -+ ); -+ -+#define FLASH_COMMAND_EXEC(io) \ -+ FLASH_COMMAND_KICK_OFF(io) \ -+ FLASH_COMMAND_WAIT_FOR_COMPLETION(io) -+ -+/* -+ * ubi32_nand_spi_er_get_feature -+ * Get Feature register -+ */ -+static uint8_t ubi32_nand_spi_er_get_feature(uint32_t reg) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ -+ /* -+ * Note that this will produce the sequence: -+ * SI [0F][REG][00][00] -+ * SO ---------[SR][SR][SR] -+ * Since the flash controller can only output 24 bits of address, this is -+ * ok for this command since the data will just repeat as long as the CS -+ * is asserted and the clock is running. -+ */ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(1) | -+ IO_XFL_CTL1_FC_ADDR; -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(0x0F) | IO_XFL_CTL2_FC_ADDR(reg << 16); -+ FLASH_COMMAND_EXEC(io); -+ -+ return io->status1 & 0xFF; -+} -+ -+/* -+ * ubi32_nand_spi_er_write_buf -+ * writes a buffer to the bus -+ * -+ * Writes 511 + 1 bytes to the bus, we have to stuff one data byte into the address. -+ */ -+static void ubi32_nand_spi_er_write_buf(const uint8_t *buf, uint32_t col) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ uint32_t tmp; -+ -+ asm volatile ( -+ " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)") \n\t" -+ " pipe_flush 0 \n\t" -+ : -+ : [port] "a" (FLASH_PORT) -+ : "cc" -+ ); -+ -+ /* -+ * Write the data into the cache -+ */ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+#ifdef SUPPORT_512_FIFO -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(511) | -+#endif -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(31) | -+ IO_XFL_CTL1_FC_ADDR; -+ -+ /* -+ * Construct the address with the first byte of data -+ */ -+ tmp = (col << 8) | *buf++; -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(0x84) | IO_XFL_CTL2_FC_ADDR(tmp); -+ -+ asm volatile ( -+ -+ /* -+ * Move 32 bytes -+ * -+ * The first word needs to be [11][22][33][33] to work around a flash -+ * controller bug. -+ */ -+ " move.2 %[tmp], (%[data])2++ \n\t" -+ " shmrg.1 %[tmp], (%[data]), %[tmp] \n\t" -+ " shmrg.1 %[tmp], (%[data])1++, %[tmp] \n\t" -+ " move.4 "D(IO_TX_FIFO)"(%[port]), %[tmp] \n\t" -+ -+ /* -+ * We're aligned again! -+ */ -+ " .rept 7 \n\t" -+ " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" -+ " .endr \n\t" -+ -+ /* -+ * Kick off the flash command -+ */ -+ " bset "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" -+ " jmpt.t .+4 \n\t" -+ " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" -+ -+#ifdef SUPPORT_512_FIFO -+ /* -+ * Fill the remaining 120 words as space becomes available -+ */ -+ "1: \n\t" -+ " cmpi "D(IO_FIFO_LEVEL)"(%[port]), #4 \n\t" -+ " jmpgt.s.t 1b \n\t" -+ " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" -+ " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" -+ " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" -+ " move.4 "D(IO_TX_FIFO)"(%[port]), (%[data])4++ \n\t" -+ " add.4 %[cnt], #-4, %[cnt] \n\t" -+ " jmpgt.t 1b \n\t" -+#endif -+ /* -+ * Wait for the transaction to finish -+ */ -+ " btst "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)") \n\t" -+ " jmpeq.f .-4 \n\t" -+ -+ : [tmp] "=&d" (tmp), -+ [data] "+&a" (buf) -+ : [column] "d" (col), -+ [port] "a" (FLASH_PORT), -+ [cnt] "d" (120) // see above comment -+ : "cc" -+ ); -+} -+ -+/* -+ * ubi32_nand_spi_er_send_rd_addr -+ * perform FC_RD: CMD + address -+ */ -+static void ubi32_nand_spi_er_send_rd_addr(uint8_t command, uint32_t address) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(4) | -+ IO_XFL_CTL1_FC_ADDR; -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(command) | IO_XFL_CTL2_FC_ADDR(address); -+ FLASH_COMMAND_EXEC(io); -+} -+ -+/* -+ * ubi32_nand_spi_er_send_cmd_addr -+ * perform FC_(xxx): CMD + address -+ */ -+static void ubi32_nand_spi_er_send_cmd_addr(uint8_t command, uint32_t address) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD) | IO_XFL_CTL1_FC_ADDR; -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(command) | IO_XFL_CTL2_FC_ADDR(address); -+ FLASH_COMMAND_EXEC(io); -+} -+ -+/* -+ * ubi32_nand_spi_er_write_disable -+ * clear the write enable bit -+ */ -+static void ubi32_nand_spi_er_write_disable(void) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(0x04); -+ FLASH_COMMAND_EXEC(io); -+} -+ -+/* -+ * ubi32_nand_spi_er_write_enable -+ * set the write enable bit -+ */ -+static void ubi32_nand_spi_er_write_enable(void) -+{ -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(0x06); -+ FLASH_COMMAND_EXEC(io); -+} -+ -+/* -+ * ubi32_nand_spi_er_busywait -+ * Wait until the chip is not busy -+ */ -+static uint8_t ubi32_nand_spi_er_busywait(void) -+{ -+ int i; -+ uint8_t data; -+ -+ /* -+ * tRD is 100us, so don't delay too long, however, tERS is -+ * 10ms so you'd better loop enough. -+ */ -+ for (i = 0; i < 200; i++) { -+ data = ubi32_nand_spi_er_get_feature(0xC0); -+ if (!(data & UBI32_NAND_SPI_ER_STATUS_OIP)) { -+ break; -+ } -+ -+ udelay(50); -+ } -+ -+ return data; -+} -+ -+/* -+ * ubi32_nand_spi_er_erase -+ * Erase a block, parameters must be block aligned -+ */ -+static int ubi32_nand_spi_er_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ struct ubi32_nand_spi_er *chip = mtd->priv; -+ int res; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: erase addr:%x len:%x\n", chip->name, instr->addr, instr->len); -+ -+ if ((instr->addr + instr->len) > mtd->size) { -+ return -EINVAL; -+ } -+ -+ if (instr->addr & (chip->device->erase_size - 1)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: erase address is not aligned %x\n", chip->name, instr->addr); -+ return -EINVAL; -+ } -+ -+ if (instr->len & (chip->device->erase_size - 1)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: erase len is not aligned %x\n", chip->name, instr->len); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&chip->lock); -+ chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; -+ -+ while (instr->len) { -+ uint32_t block = instr->addr >> 17; -+ uint32_t row = block << 6; -+ uint8_t stat; -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: block erase row:%x block:%x addr:%x rem:%x\n", chip->name, row, block, instr->addr, instr->len); -+ -+ /* -+ * Test for bad block -+ */ -+ if (test_bit(block, chip->bbt)) { -+ instr->fail_addr = block << 17; -+ instr->state = MTD_ERASE_FAILED; -+ res = -EBADMSG; -+ goto done; -+ } -+ -+ ubi32_nand_spi_er_write_enable(); -+ -+ /* -+ * Block erase -+ */ -+ ubi32_nand_spi_er_send_cmd_addr(0xD8, row); -+ -+ /* -+ * Wait -+ */ -+ stat = ubi32_nand_spi_er_busywait(); -+ if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { -+ instr->fail_addr = block << 17; -+ instr->state = MTD_ERASE_FAILED; -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); -+ -+ /* -+ * Chip is stuck? -+ */ -+ res = -EIO; -+ goto done; -+ } -+ -+ /* -+ * Check the status register -+ */ -+ if (stat & UBI32_NAND_SPI_ER_STATUS_E_FAIL) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: E_FAIL signalled (%02x)\n", chip->name, stat); -+ instr->fail_addr = block << 17; -+ instr->state = MTD_ERASE_FAILED; -+ goto done; -+ } -+ -+ /* -+ * Next -+ */ -+ block++; -+ instr->len -= chip->device->erase_size; -+ instr->addr += chip->device->erase_size; -+ } -+ -+ instr->state = MTD_ERASE_DONE; -+ -+ mutex_unlock(&chip->lock); -+ return 0; -+ -+done: -+ ubi32_nand_spi_er_write_disable(); -+ -+ mutex_unlock(&chip->lock); -+ -+ mtd_erase_callback(instr); -+ return 0; -+} -+ -+/* -+ * ubi32_nand_spi_er_read -+ * -+ * return -EUCLEAN: ecc error recovered -+ * return -EBADMSG: ecc error not recovered -+*/ -+static int ubi32_nand_spi_er_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ struct ubi32_nand_spi_er *chip = mtd->priv; -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ -+ uint32_t row; -+ uint32_t column; -+ int retval = 0; -+ uint32_t *pbuf = (uint32_t *)buf; -+ -+ *retlen = 0; -+ DEBUG(MTD_DEBUG_LEVEL2, "%s: read block from %llx len %d into %p\n", chip->name, from, len, buf); -+ -+ /* -+ * buf should be aligned -+ */ -+ if ((uint32_t)buf & 0x03) { -+ return -EINVAL; -+ } -+ -+ /* -+ * Zero length reads, nothing to do -+ */ -+ if (len == 0) { -+ return 0; -+ } -+ -+ /* -+ * Reject reads which go over the end of the flash -+ */ -+ if ((from + len) > mtd->size) { -+ return -EINVAL; -+ } -+ -+ /* -+ * Get the row and column address to start at -+ */ -+ row = from >> 11; -+ column = from & 0x7FF; -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: row=%x %d column=%x %d last_row=%x %d\n", chip->name, row, row, column, column, chip->last_row, chip->last_row); -+ -+ /* -+ * Read the data from the chip -+ */ -+ mutex_lock(&chip->lock); -+ while (len) { -+ uint8_t stat; -+ size_t toread; -+ int i; -+ int tmp; -+ -+ /* -+ * Figure out how much to read -+ * -+ * If we are reading from the middle of a page then the most we -+ * can read is to the end of the page -+ */ -+ toread = len; -+ if (toread > (chip->device->page_size - column)) { -+ toread = chip->device->page_size - column; -+ } -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: buf=%p toread=%x row=%x column=%x last_row=%x\n", chip->name, pbuf, toread, row, column, chip->last_row); -+ -+ if (chip->last_row != row) { -+ /* -+ * Check if the block is bad -+ */ -+ if (test_bit(UBI32_NAND_SPI_ER_BLOCK_FROM_ROW(row), chip->bbt)) { -+ mutex_unlock(&chip->lock); -+ return -EBADMSG; -+ } -+ -+ /* -+ * Load the appropriate page -+ */ -+ ubi32_nand_spi_er_send_cmd_addr(0x13, row); -+ -+ /* -+ * Wait -+ */ -+ stat = ubi32_nand_spi_er_busywait(); -+ if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); -+ -+ /* -+ * Chip is stuck? -+ */ -+ mutex_unlock(&chip->lock); -+ return -EIO; -+ } -+ -+ /* -+ * Check the ECC bits -+ */ -+ stat >>= 4; -+ if (stat == 1) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: ECC recovered, row=%x\n", chip->name, row); -+ retval = -EUCLEAN; -+ } -+ if (stat == 2) { -+ DEBUG(MTD_DEBUG_LEVEL0, "%s: failed ECC, row=%x\n", chip->name, row); -+ chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; -+ mutex_unlock(&chip->lock); -+ return -EBADMSG; -+ } -+ -+ } -+ -+ chip->last_row = row; -+ -+ /* -+ * Read out the data: -+ * We can always read a little too much since there is the -+ * OOB after byte addr 2047. The most we'll overread is 3 bytes. -+ */ -+ if (((uint32_t)pbuf & 0x03) == 0) { -+ /* -+ * Aligned read -+ */ -+ tmp = toread & (~0x03); -+ for (i = 0; i < tmp; i += 4) { -+ ubi32_nand_spi_er_send_rd_addr(0x03, column << 8); -+ *pbuf++ = io->status1; -+ column += 4; -+ } -+ } else { -+ /* -+ * Unaligned read -+ */ -+ tmp = toread & (~0x03); -+ for (i = 0; i < tmp; i += 4) { -+ ubi32_nand_spi_er_send_rd_addr(0x03, column << 8); -+ memcpy(pbuf, &io->status1, 4); -+ column += 4; -+ } -+ } -+ -+ /* -+ * Fill in any single bytes -+ */ -+ tmp = toread & 0x03; -+ if (tmp) { -+ uint8_t *bbuf = pbuf; -+ uint32_t val; -+ ubi32_nand_spi_er_send_rd_addr(0x03, column << 8); -+ val = io->status1; -+ for (i = 0; i < tmp; i++) { -+ *bbuf++ = val >> 24; -+ val <<= 8; -+ } -+ } -+ -+ len -= toread; -+ *retlen += toread; -+ -+ /* -+ * For the next page, increment the row and always start at column 0 -+ */ -+ column = 0; -+ row++; -+ } -+ -+ mutex_unlock(&chip->lock); -+ return retval; -+} -+ -+/* -+ * ubi32_nand_spi_er_write -+ */ -+#define WRITE_NOT_ALIGNED(x) ((x & (device->write_size - 1)) != 0) -+static int ubi32_nand_spi_er_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ struct ubi32_nand_spi_er *chip = mtd->priv; -+ const struct ubi32_nand_spi_er_device *device = chip->device; -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ uint32_t row; -+ uint32_t col; -+ int res = 0; -+ size_t towrite; -+ -+ DEBUG(MTD_DEBUG_LEVEL2, "%s: write block to %llx len %d from %p\n", chip->name, to, len, buf); -+ -+ *retlen = 0; -+ -+ /* -+ * nothing to write -+ */ -+ if (!len) { -+ return 0; -+ } -+ -+ /* -+ * Reject writes which go over the end of the flash -+ */ -+ if ((to + len) > mtd->size) { -+ return -EINVAL; -+ } -+ -+ /* -+ * buf should be aligned to 16 bits -+ */ -+ if ((uint32_t)buf & 0x01) { -+ return -EINVAL; -+ } -+ -+ /* -+ * Check to see if everything is page aligned -+ */ -+ if (WRITE_NOT_ALIGNED(to) || WRITE_NOT_ALIGNED(len)) { -+ printk(KERN_NOTICE "ubi32_nand_spi_er_write: Attempt to write non page aligned data\n"); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&chip->lock); -+ -+ io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; -+ -+ chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; -+ -+ /* -+ * If the first write is a partial write then write at most the number of -+ * bytes to get us page aligned and then the remainder will be -+ * page aligned. The last bit may be a partial page as well. -+ */ -+ col = to & (device->page_size - 1); -+ towrite = device->page_size - col; -+ if (towrite > len) { -+ towrite = len; -+ } -+ -+ /* -+ * Write the data -+ */ -+ row = to >> 11; -+ while (len) { -+ uint8_t stat; -+ uint32_t my_towrite; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: write %p to row:%x col:%x len:%x rem:%x\n", chip->name, buf, row, col, towrite, len); -+ -+ ubi32_nand_spi_er_write_enable(); -+ -+ /* -+ * Move the data into the cache -+ */ -+ my_towrite = towrite; -+ while (my_towrite) { -+ uint32_t len = my_towrite; -+ if (len > 32) { -+ len = 32; -+ } -+ -+ ubi32_nand_spi_er_write_buf(buf, col); -+ buf += len; -+ col += len; -+ my_towrite -= len; -+ } -+ -+ /* -+ * Program execute -+ */ -+ ubi32_nand_spi_er_send_cmd_addr(0x10, row); -+ -+ /* -+ * Wait -+ */ -+ stat = ubi32_nand_spi_er_busywait(); -+ if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); -+ -+ /* -+ * Chip is stuck? -+ */ -+ res = -EIO; -+ goto done; -+ } -+ -+ if (stat & (1 << 3)) { -+ res = -EBADMSG; -+ goto done; -+ } -+ -+ row++; -+ len -= towrite; -+ *retlen += towrite; -+ -+ /* -+ * At this point, we are always page aligned so start at column 0. -+ * Note we may not have a full page to write at the end, hence the -+ * check if towrite > len. -+ */ -+ col = 0; -+ towrite = device->page_size; -+ if (towrite > len) { -+ towrite = len; -+ } -+ } -+ -+ io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; -+ -+ mutex_unlock(&chip->lock); -+ return res; -+ -+done: -+ ubi32_nand_spi_er_write_disable(); -+ -+ io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; -+ -+ mutex_unlock(&chip->lock); -+ -+ return res; -+} -+ -+/* -+ * ubi32_nand_spi_er_isbad -+ */ -+static int ubi32_nand_spi_er_isbad(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct ubi32_nand_spi_er *chip = mtd->priv; -+ uint32_t block; -+ -+ if (ofs & (chip->device->erase_size - 1)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs); -+ return -EINVAL; -+ } -+ -+ block = ofs >> 17; -+ -+ return test_bit(block, chip->bbt); -+} -+ -+/* -+ * ubi32_nand_spi_er_markbad -+ */ -+static int ubi32_nand_spi_er_markbad(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct ubi32_nand_spi_er *chip = mtd->priv; -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ uint32_t block; -+ uint32_t row; -+ int res = 0; -+ uint8_t stat; -+ -+ if (ofs & (chip->device->erase_size - 1)) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs); -+ return -EINVAL; -+ } -+ -+ block = ofs >> 17; -+ -+ /* -+ * If it's already marked bad, no need to mark it -+ */ -+ if (test_bit(block, chip->bbt)) { -+ return 0; -+ } -+ -+ /* -+ * Mark it in our cache -+ */ -+ __set_bit(block, chip->bbt); -+ -+ /* -+ * Write the user bad block mark. If it fails, then we really -+ * can't do anything about it. -+ */ -+ mutex_lock(&chip->lock); -+ chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; -+ -+ ubi32_nand_spi_er_write_enable(); -+ -+ /* -+ * Write the mark -+ */ -+ io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(6); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(0x84); -+ -+ asm volatile ( -+ " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)") \n\t" -+ " pipe_flush 0 \n\t" -+ -+ /* -+ * Move the data into the FIFO -+ */ -+ " move.4 "D(IO_TX_FIFO)"(%[port]), %[word1] \n\t" -+ " move.4 "D(IO_TX_FIFO)"(%[port]), %[word2] \n\t" -+ -+ /* -+ * Kick off the flash command -+ */ -+ " bset "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" -+ " jmpt.t .+4 \n\t" -+ " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" -+ -+ /* -+ * Wait for the transaction to finish -+ */ -+ " btst "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)") \n\t" -+ " jmpeq.f .-4 \n\t" -+ -+ : -+ : [word1] "d" (0x0800dead | (UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET << 16)), -+ [word2] "d" (0xbeef0000), -+ [port] "a" (FLASH_PORT) -+ : "cc" -+ ); -+ -+ io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; -+ -+ /* -+ * Program execute -+ */ -+ row = block << 6; -+ ubi32_nand_spi_er_send_cmd_addr(0x10, row); -+ -+ /* -+ * Wait -+ */ -+ stat = ubi32_nand_spi_er_busywait(); -+ if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); -+ -+ /* -+ * Chip is stuck? -+ */ -+ res = -EIO; -+ goto done; -+ } -+ -+ if (stat & (1 << 3)) { -+ res = -EBADMSG; -+ } -+ -+done: -+ ubi32_nand_spi_er_write_disable(); -+ -+ mutex_unlock(&chip->lock); -+ -+ return res; -+} -+ -+/* -+ * ubi32_nand_spi_er_read_bbt -+ */ -+static int ubi32_nand_spi_er_read_bbt(struct ubi32_nand_spi_er *chip) -+{ -+ int j; -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ -+ for (j = 0; j < chip->device->blocks; j++) { -+ unsigned short row = j << 6; -+ uint8_t stat; -+ -+ /* -+ * Read Page -+ */ -+ ubi32_nand_spi_er_send_cmd_addr(0x13, row); -+ -+ /* -+ * Wait -+ */ -+ stat = ubi32_nand_spi_er_busywait(); -+ if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) { -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat); -+ -+ /* -+ * Chip is stuck? -+ */ -+ return -EIO; -+ } -+ -+ /* -+ * Check factory bad block mark -+ */ -+ ubi32_nand_spi_er_send_rd_addr(0x03, 0x080000); -+ -+ if ((io->status1 >> 24) != 0xFF) { -+ chip->nbb++; -+ __set_bit(j, chip->bbt); -+ continue; -+ } -+ -+ ubi32_nand_spi_er_send_rd_addr(0x03, 0x080000 | (UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET << 8)); -+ if (io->status1 == 0xdeadbeef) { -+ chip->nbb++; -+ __set_bit(j, chip->bbt); -+ } -+ } -+ -+#if defined(CONFIG_MTD_DEBUG) && (MTD_DEBUG_LEVEL3 <= CONFIG_MTD_DEBUG_VERBOSE) -+ printk("%s: Bad Block Table:", chip->name); -+ for (j = 0; j < chip->device->blocks; j++) { -+ if ((j % 64) == 0) { -+ printk("\n%s: block %03x: ", chip->name, j); -+ } -+ printk("%c", test_bit(j, chip->bbt) ? 'X' : '.'); -+ } -+ printk("\n%s: Bad Block Numbers: ", chip->name); -+ for (j = 0; j < chip->device->blocks; j++) { -+ if (test_bit(j, chip->bbt)) { -+ printk("%x ", j); -+ } -+ } -+ printk("\n"); -+#endif -+ -+ return 0; -+} -+ -+#ifndef MODULE -+/* -+ * Called at boot time: -+ * -+ * ubi32_nand_spi_er=read_only -+ * if read_only specified then do not unlock device -+ */ -+static int __init ubi32_nand_spi_er_setup(char *str) -+{ -+ if (str && (strncasecmp(str, "read_only", 9) == 0)) { -+ read_only = 1; -+ } -+ return 0; -+} -+ -+__setup("ubi32_nand_spi_er=", ubi32_nand_spi_er_setup); -+#endif -+ -+/* -+ * ubi32_nand_spi_er_probe -+ * Detect and initialize ubi32_nand_spi_er device. -+ */ -+static int __devinit ubi32_nand_spi_er_probe(struct platform_device *pdev) -+{ -+ uint32_t i; -+ uint32_t id; -+ int res; -+ size_t bbt_bytes; -+ struct ubi32_nand_spi_er *chip; -+ const struct ubi32_nand_spi_er_device *device; -+ struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT; -+ -+ /* -+ * Reset -+ */ -+ for (i = 0; i < 2; i++) { -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(0xFF); -+ FLASH_COMMAND_EXEC(io); -+ udelay(250); -+ } -+ udelay(1000); -+ -+ /* -+ * Read out ID -+ */ -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(2) | -+ IO_XFL_CTL1_FC_ADDR; -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(0x9F); -+ FLASH_COMMAND_EXEC(io); -+ -+ id = io->status1 >> 16; -+ device = ubi32_nand_spi_er_devices; -+ for (i = 0; i < ARRAY_SIZE(ubi32_nand_spi_er_devices); i++) { -+ if (device->id == id) { -+ break; -+ } -+ device++; -+ } -+ if (i == ARRAY_SIZE(ubi32_nand_spi_er_devices)) { -+ return -ENODEV; -+ } -+ -+ /* -+ * Initialize our chip structure -+ */ -+ bbt_bytes = DIV_ROUND_UP(device->blocks, BITS_PER_BYTE); -+ chip = kzalloc(sizeof(struct ubi32_nand_spi_er) + bbt_bytes, GFP_KERNEL); -+ if (!chip) { -+ return -ENOMEM; -+ } -+ snprintf(chip->name, sizeof(chip->name), "%s", device->name); -+ -+ chip->device = device; -+ chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID; -+ -+ mutex_init(&chip->lock); -+ -+ chip->mtd.type = MTD_NANDFLASH; -+ chip->mtd.flags = MTD_WRITEABLE; -+ -+ /* -+ * #blocks * block size * n blocks -+ */ -+ chip->mtd.size = device->blocks * device->pages_per_block * device->page_size; -+ chip->mtd.erasesize = device->erase_size; -+ -+ /* -+ * 1 page, optionally we can support partial write (512) -+ */ -+ chip->mtd.writesize = device->write_size; -+ chip->mtd.name = device->name; -+ chip->mtd.erase = ubi32_nand_spi_er_erase; -+ chip->mtd.read = ubi32_nand_spi_er_read; -+ chip->mtd.write = ubi32_nand_spi_er_write; -+ chip->mtd.block_isbad = ubi32_nand_spi_er_isbad; -+ chip->mtd.block_markbad = ubi32_nand_spi_er_markbad; -+ chip->mtd.priv = chip; -+ -+ /* -+ * Cache the bad block table -+ */ -+ res = ubi32_nand_spi_er_read_bbt(chip); -+ if (res) { -+ kfree(chip); -+ return res; -+ } -+ -+ /* -+ * Un/lock the chip -+ */ -+ io->ctl0 |= IO_XFL_CTL0_MCB_LOCK; -+ io->ctl1 &= ~IO_XFL_CTL1_MASK; -+ io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(2); -+ io->ctl2 = IO_XFL_CTL2_FC_CMD(0x1F); -+ -+ if (read_only) { -+ i = 0xa0380000; -+ } else { -+ i = 0xa0000000; -+ } -+ asm volatile ( -+ " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)") \n\t" -+ " pipe_flush 0 \n\t" -+ -+ /* -+ * Move the data into the FIFO -+ */ -+ " move.4 "D(IO_TX_FIFO)"(%[port]), %[word1] \n\t" -+ -+ /* -+ * Kick off the flash command -+ */ -+ " bset "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)") \n\t" -+ " jmpt.t .+4 \n\t" -+ " bset "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)") \n\t" -+ -+ /* -+ * Wait for the transaction to finish -+ */ -+ " btst "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)") \n\t" -+ " jmpeq.f .-4 \n\t" -+ -+ : -+ : [word1] "d" (i), -+ [port] "a" (FLASH_PORT) -+ : "cc" -+ ); -+ io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK; -+ -+ dev_set_drvdata(&pdev->dev, chip); -+ -+ printk(KERN_INFO "%s: added device size: %u KBytes %lu bad blocks %s\n", chip->mtd.name, DIV_ROUND_UP(chip->mtd.size, 1024), chip->nbb, read_only ? "[read only]" : ""); -+ return add_mtd_device(&chip->mtd); -+} -+ -+/* -+ * ubi32_nand_spi_er_remove -+ */ -+static int __devexit ubi32_nand_spi_er_remove(struct platform_device *pdev) -+{ -+ struct ubi32_nand_spi_er *chip = dev_get_drvdata(&pdev->dev); -+ int status; -+ -+ DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", chip->name); -+ -+ status = del_mtd_device(&chip->mtd); -+ if (status == 0) { -+ kfree(chip); -+ } -+ -+ dev_set_drvdata(&pdev->dev, NULL); -+ return status; -+} -+ -+static struct platform_device *ubi32_nand_spi_er_device; -+ -+static struct platform_driver ubi32_nand_spi_er_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ -+ .probe = ubi32_nand_spi_er_probe, -+ .remove = ubi32_nand_spi_er_remove, -+}; -+ -+/* -+ * ubi32_nand_spi_er_init -+ */ -+static int __init ubi32_nand_spi_er_init(void) -+{ -+ int ret; -+ -+ ret = platform_driver_register(&ubi32_nand_spi_er_driver); -+ -+ if (ret) { -+ return ret; -+ } -+ -+ ubi32_nand_spi_er_device = platform_device_alloc(DRIVER_NAME, 0); -+ if (!ubi32_nand_spi_er_device) { -+ return -ENOMEM; -+ } -+ -+ ret = platform_device_add(ubi32_nand_spi_er_device); -+ if (ret) { -+ platform_device_put(ubi32_nand_spi_er_device); -+ platform_driver_unregister(&ubi32_nand_spi_er_driver); -+ } -+ -+ return ret; -+} -+module_init(ubi32_nand_spi_er_init); -+ -+/* -+ * ubi32_nand_spi_er_exit -+ */ -+static void __exit ubi32_nand_spi_er_exit(void) -+{ -+ platform_device_unregister(ubi32_nand_spi_er_device); -+ platform_driver_unregister(&ubi32_nand_spi_er_driver); -+} -+module_exit(ubi32_nand_spi_er_exit); -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Patrick Tjin"); -+MODULE_DESCRIPTION("MTD ubi32_nand_spi_er driver for ubicom32 SPI flash controller."); -diff -ruN linux-2.6.30.10/drivers/net/Kconfig linux-2.6.30.10-ubi/drivers/net/Kconfig ---- linux-2.6.30.10/drivers/net/Kconfig 2009-12-14 11:47:19.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/net/Kconfig 2009-12-14 11:47:17.000000000 +0200 -@@ -2540,6 +2540,19 @@ +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -2540,6 +2540,19 @@ config JME To compile this driver as a module, choose M here. The module will be called jme. @@ -45986,919 +153,17 @@ diff -ruN linux-2.6.30.10/drivers/net/Kconfig linux-2.6.30.10-ubi/drivers/net/Kc endif # NETDEV_1000 # -diff -ruN linux-2.6.30.10/drivers/net/Makefile linux-2.6.30.10-ubi/drivers/net/Makefile ---- linux-2.6.30.10/drivers/net/Makefile 2009-12-14 11:48:38.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/net/Makefile 2009-12-14 11:48:40.000000000 +0200 -@@ -272,3 +272,5 @@ +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -272,3 +272,5 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o obj-$(CONFIG_SFC) += sfc/ obj-$(CONFIG_WIMAX) += wimax/ + +obj-$(CONFIG_UBICOM32_GMAC) += ubi32-eth.o -diff -ruN linux-2.6.30.10/drivers/net/ubi32-eth.c linux-2.6.30.10-ubi/drivers/net/ubi32-eth.c ---- linux-2.6.30.10/drivers/net/ubi32-eth.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/net/ubi32-eth.c 2009-12-11 11:45:18.000000000 +0200 -@@ -0,0 +1,760 @@ -+/* -+ * drivers/net/ubi32-eth.c -+ * Ubicom32 ethernet TIO interface driver. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+/* -+ * ubi32_eth.c -+ * Ethernet driver for Ip5k/Ip7K -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define UBICOM32_USE_NAPI /* define this to use NAPI instead of tasklet */ -+//#define UBICOM32_USE_POLLING /* define this to use polling instead of interrupt */ -+#include "ubi32-eth.h" -+ -+/* -+ * TODO: -+ * mac address from flash -+ * multicast filter -+ * ethtool support -+ * sysfs support -+ * skb->nrfrag support -+ * ioctl -+ * monitor phy status -+ */ -+ -+extern int ubi32_ocm_skbuf_max, ubi32_ocm_skbuf, ubi32_ddr_skbuf; -+static const char *eth_if_name[UBI32_ETH_NUM_OF_DEVICES] = -+ {"eth_lan", "eth_wan"}; -+static struct net_device *ubi32_eth_devices[UBI32_ETH_NUM_OF_DEVICES] = -+ {NULL, NULL}; -+static u8_t mac_addr[UBI32_ETH_NUM_OF_DEVICES][ETH_ALEN] = { -+ {0x00, 0x03, 0x64, 'l', 'a', 'n'}, -+ {0x00, 0x03, 0x64, 'w', 'a', 'n'}}; -+ -+#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB)) -+static inline struct sk_buff *ubi32_alloc_skb_ocm(struct net_device *dev, unsigned int length) -+{ -+ return __dev_alloc_skb(length, GFP_ATOMIC | __GFP_NOWARN | __GFP_NORETRY | GFP_DMA); -+} -+#endif -+ -+static inline struct sk_buff *ubi32_alloc_skb(struct net_device *dev, unsigned int length) -+{ -+ return __dev_alloc_skb(length, GFP_ATOMIC | __GFP_NOWARN); -+} -+ -+static void ubi32_eth_vp_rxtx_enable(struct net_device *dev) -+{ -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ priv->regs->command = UBI32_ETH_VP_CMD_RX_ENABLE | UBI32_ETH_VP_CMD_TX_ENABLE; -+ priv->regs->int_mask = (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX); -+ ubicom32_set_interrupt(priv->vp_int_bit); -+} -+ -+static void ubi32_eth_vp_rxtx_stop(struct net_device *dev) -+{ -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ priv->regs->command = 0; -+ priv->regs->int_mask = 0; -+ ubicom32_set_interrupt(priv->vp_int_bit); -+ -+ /* Wait for graceful shutdown */ -+ while (priv->regs->status & (UBI32_ETH_VP_STATUS_RX_STATE | UBI32_ETH_VP_STATUS_TX_STATE)); -+} -+ -+/* -+ * ubi32_eth_tx_done() -+ */ -+static int ubi32_eth_tx_done(struct net_device *dev) -+{ -+ struct ubi32_eth_private *priv; -+ struct sk_buff *skb; -+ volatile void *pdata; -+ struct ubi32_eth_dma_desc *desc; -+ u32_t count = 0; -+ -+ priv = netdev_priv(dev); -+ -+ priv->regs->int_status &= ~UBI32_ETH_VP_INT_TX; -+ while (priv->tx_tail != priv->regs->tx_out) { -+ pdata = priv->regs->tx_dma_ring[priv->tx_tail]; -+ BUG_ON(pdata == NULL); -+ -+ skb = container_of((void *)pdata, struct sk_buff, cb); -+ desc = (struct ubi32_eth_dma_desc *)pdata; -+ if (unlikely(!(desc->status & UBI32_ETH_VP_TX_OK))) { -+ dev->stats.tx_errors++; -+ } else { -+ dev->stats.tx_packets++; -+ dev->stats.tx_bytes += skb->len; -+ } -+ dev_kfree_skb_any(skb); -+ priv->regs->tx_dma_ring[priv->tx_tail] = NULL; -+ priv->tx_tail = (priv->tx_tail + 1) & TX_DMA_RING_MASK; -+ count++; -+ } -+ -+ if (unlikely(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) { -+ spin_lock(&priv->lock); -+ if (priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL) { -+ priv->regs->status &= ~UBI32_ETH_VP_STATUS_TX_Q_FULL; -+ netif_wake_queue(dev); -+ } -+ spin_unlock(&priv->lock); -+ } -+ return count; -+} -+ -+/* -+ * ubi32_eth_receive() -+ * To avoid locking overhead, this is called only -+ * by tasklet when not using NAPI, or -+ * by NAPI poll when using NAPI. -+ * return number of frames processed -+ */ -+static int ubi32_eth_receive(struct net_device *dev, int quota) -+{ -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ unsigned short rx_in = priv->regs->rx_in; -+ struct sk_buff *skb; -+ struct ubi32_eth_dma_desc *desc = NULL; -+ volatile void *pdata; -+ -+ int extra_reserve_adj; -+ int extra_alloc = UBI32_ETH_RESERVE_SPACE + UBI32_ETH_TRASHED_MEMORY; -+ int replenish_cnt, count = 0; -+ int replenish_max = RX_DMA_MAX_QUEUE_SIZE; -+#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB)) -+ if (likely(dev == ubi32_eth_devices[0])) -+ replenish_max = min(ubi32_ocm_skbuf_max, RX_DMA_MAX_QUEUE_SIZE);; -+#endif -+ -+ if (unlikely(rx_in == priv->regs->rx_out)) -+ priv->vp_stats.rx_q_full_cnt++; -+ -+ priv->regs->int_status &= ~UBI32_ETH_VP_INT_RX; -+ while (priv->rx_tail != priv->regs->rx_out) { -+ if (unlikely(count == quota)) { -+ /* There is still frame pending to be processed */ -+ priv->vp_stats.rx_throttle++; -+ break; -+ } -+ -+ pdata = priv->regs->rx_dma_ring[priv->rx_tail]; -+ BUG_ON(pdata == NULL); -+ -+ desc = (struct ubi32_eth_dma_desc *)pdata; -+ skb = container_of((void *)pdata, struct sk_buff, cb); -+ count++; -+ priv->regs->rx_dma_ring[priv->rx_tail] = NULL; -+ priv->rx_tail = ((priv->rx_tail + 1) & RX_DMA_RING_MASK); -+ -+ /* -+ * Check only RX_OK bit here. -+ * The rest of status word is used as timestamp -+ */ -+ if (unlikely(!(desc->status & UBI32_ETH_VP_RX_OK))) { -+ dev->stats.rx_errors++; -+ dev_kfree_skb_any(skb); -+ continue; -+ } -+ -+ skb_put(skb, desc->data_len); -+ skb->dev = dev; -+ skb->protocol = eth_type_trans(skb, dev); -+ skb->ip_summed = CHECKSUM_NONE; -+ dev->stats.rx_bytes += skb->len; -+ dev->stats.rx_packets++; -+#ifndef UBICOM32_USE_NAPI -+ netif_rx(skb); -+#else -+ netif_receive_skb(skb); -+#endif -+ } -+ -+ /* fill in more descripor for VP*/ -+ replenish_cnt = replenish_max - -+ ((RX_DMA_RING_SIZE + rx_in - priv->rx_tail) & RX_DMA_RING_MASK); -+ if (replenish_cnt > 0) { -+#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB)) -+ /* -+ * black magic for perforamnce: -+ * Try to allocate skb from OCM only for first Ethernet I/F. -+ * Also limit number of RX buffers to 21 due to limited OCM. -+ */ -+ if (likely(dev == ubi32_eth_devices[0])) { -+ do { -+ skb = ubi32_alloc_skb_ocm(dev, RX_BUF_SIZE + extra_alloc); -+ if (!skb) { -+ break; -+ } -+ /* set up dma descriptor */ -+ ubi32_ocm_skbuf++; -+ desc = (struct ubi32_eth_dma_desc *)skb->cb; -+ extra_reserve_adj = -+ ((u32)skb->data + UBI32_ETH_RESERVE_SPACE + ETH_HLEN) & -+ (CACHE_LINE_SIZE - 1); -+ skb_reserve(skb, UBI32_ETH_RESERVE_SPACE - extra_reserve_adj); -+ desc->data_pointer = skb->data; -+ desc->buffer_len = RX_BUF_SIZE + UBI32_ETH_TRASHED_MEMORY; -+ desc->data_len = 0; -+ desc->status = 0; -+ priv->regs->rx_dma_ring[rx_in] = desc; -+ rx_in = (rx_in + 1) & RX_DMA_RING_MASK; -+ } while (--replenish_cnt > 0); -+ } -+#endif -+ -+ while (replenish_cnt-- > 0) { -+ skb = ubi32_alloc_skb(dev, RX_BUF_SIZE + extra_alloc); -+ if (!skb) { -+ priv->vp_stats.rx_alloc_err++; -+ break; -+ } -+ /* set up dma descriptor */ -+ ubi32_ddr_skbuf++; -+ desc = (struct ubi32_eth_dma_desc *)skb->cb; -+ extra_reserve_adj = -+ ((u32)skb->data + UBI32_ETH_RESERVE_SPACE + ETH_HLEN) & -+ (CACHE_LINE_SIZE - 1); -+ skb_reserve(skb, UBI32_ETH_RESERVE_SPACE - extra_reserve_adj); -+ desc->data_pointer = skb->data; -+ desc->buffer_len = RX_BUF_SIZE + UBI32_ETH_TRASHED_MEMORY; -+ desc->data_len = 0; -+ desc->status = 0; -+ priv->regs->rx_dma_ring[rx_in] = desc; -+ rx_in = (rx_in + 1) & RX_DMA_RING_MASK; -+ } -+ -+ wmb(); -+ priv->regs->rx_in = rx_in; -+ ubicom32_set_interrupt(priv->vp_int_bit); -+ } -+ -+ if (likely(count > 0)) { -+ dev->last_rx = jiffies; -+ } -+ return count; -+} -+ -+#ifdef UBICOM32_USE_NAPI -+static int ubi32_eth_napi_poll(struct napi_struct *napi, int budget) -+{ -+ struct ubi32_eth_private *priv = container_of(napi, struct ubi32_eth_private, napi); -+ struct net_device *dev = priv->dev; -+ u32_t count; -+ -+ if (priv->tx_tail != priv->regs->tx_out) { -+ ubi32_eth_tx_done(dev); -+ } -+ -+ count = ubi32_eth_receive(dev, budget); -+ -+ if (count < budget) { -+ napi_complete(napi); -+ priv->regs->int_mask |= (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX); -+ if ((priv->rx_tail != priv->regs->rx_out) || (priv->tx_tail != priv->regs->tx_out)) { -+ if (napi_reschedule(napi)) { -+ priv->regs->int_mask = 0; -+ } -+ } -+ } -+ return count; -+} -+ -+#else -+static void ubi32_eth_do_tasklet(unsigned long arg) -+{ -+ struct net_device *dev = (struct net_device *)arg; -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ -+ if (priv->tx_tail != priv->regs->tx_out) { -+ ubi32_eth_tx_done(dev); -+ } -+ -+ /* always call receive to process new RX frame as well as replenish RX buffers */ -+ ubi32_eth_receive(dev, UBI32_RX_BOUND); -+ -+ priv->regs->int_mask |= (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX); -+ if ((priv->rx_tail != priv->regs->rx_out) || (priv->tx_tail != priv->regs->tx_out)) { -+ priv->regs->int_mask = 0; -+ tasklet_schedule(&priv->tsk); -+ } -+} -+#endif -+ -+#if defined(UBICOM32_USE_POLLING) -+static struct timer_list eth_poll_timer; -+ -+static void ubi32_eth_poll(unsigned long arg) -+{ -+ struct net_device *dev; -+ struct ubi32_eth_private *priv; -+ int i; -+ -+ for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) { -+ dev = ubi32_eth_devices[i]; -+ if (dev && (dev->flags & IFF_UP)) { -+ priv = netdev_priv(dev); -+#ifdef UBICOM32_USE_NAPI -+ napi_schedule(&priv->napi); -+#else -+ tasklet_schedule(&priv->tsk); -+#endif -+ } -+ } -+ -+ eth_poll_timer.expires = jiffies + 2; -+ add_timer(ð_poll_timer); -+} -+ -+#else -+static irqreturn_t ubi32_eth_interrupt(int irq, void *dev_id) -+{ -+ struct ubi32_eth_private *priv; -+ -+ struct net_device *dev = (struct net_device *)dev_id; -+ BUG_ON(irq != dev->irq); -+ -+ priv = netdev_priv(dev); -+ if (unlikely(!(priv->regs->int_status & priv->regs->int_mask))) { -+ return IRQ_NONE; -+ } -+ -+ /* -+ * Disable port interrupt -+ */ -+#ifdef UBICOM32_USE_NAPI -+ if (napi_schedule_prep(&priv->napi)) { -+ priv->regs->int_mask = 0; -+ __napi_schedule(&priv->napi); -+ } -+#else -+ priv->regs->int_mask = 0; -+ tasklet_schedule(&priv->tsk); -+#endif -+ return IRQ_HANDLED; -+} -+#endif -+ -+/* -+ * ubi32_eth_open -+ */ -+static int ubi32_eth_open(struct net_device *dev) -+{ -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ int err; -+ -+ printk(KERN_INFO "eth open %s\n",dev->name); -+#ifndef UBICOM32_USE_POLLING -+ /* request_region() */ -+ err = request_irq(dev->irq, ubi32_eth_interrupt, IRQF_DISABLED, dev->name, dev); -+ if (err) { -+ printk(KERN_WARNING "fail to request_irq %d\n",err); -+ return -ENODEV; -+ } -+#endif -+#ifdef UBICOM32_USE_NAPI -+ napi_enable(&priv->napi); -+#else -+ tasklet_init(&priv->tsk, ubi32_eth_do_tasklet, (unsigned long)dev); -+#endif -+ -+ /* call receive to supply RX buffers */ -+ ubi32_eth_receive(dev, RX_DMA_MAX_QUEUE_SIZE); -+ -+ /* check phy status and call netif_carrier_on */ -+ ubi32_eth_vp_rxtx_enable(dev); -+ netif_start_queue(dev); -+ return 0; -+} -+ -+static int ubi32_eth_close(struct net_device *dev) -+{ -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ volatile void *pdata; -+ struct sk_buff *skb; -+ -+#ifndef UBICOM32_USE_POLLING -+ free_irq(dev->irq, dev); -+#endif -+ netif_stop_queue(dev); /* can't transmit any more */ -+#ifdef UBICOM32_USE_NAPI -+ napi_disable(&priv->napi); -+#else -+ tasklet_kill(&priv->tsk); -+#endif -+ ubi32_eth_vp_rxtx_stop(dev); -+ -+ /* -+ * RX clean up -+ */ -+ while (priv->rx_tail != priv->regs->rx_in) { -+ pdata = priv->regs->rx_dma_ring[priv->rx_tail]; -+ skb = container_of((void *)pdata, struct sk_buff, cb); -+ priv->regs->rx_dma_ring[priv->rx_tail] = NULL; -+ dev_kfree_skb_any(skb); -+ priv->rx_tail = ((priv->rx_tail + 1) & RX_DMA_RING_MASK); -+ } -+ priv->regs->rx_in = 0; -+ priv->regs->rx_out = priv->regs->rx_in; -+ priv->rx_tail = priv->regs->rx_in; -+ -+ /* -+ * TX clean up -+ */ -+ BUG_ON(priv->regs->tx_out != priv->regs->tx_in); -+ ubi32_eth_tx_done(dev); -+ BUG_ON(priv->tx_tail != priv->regs->tx_in); -+ priv->regs->tx_in = 0; -+ priv->regs->tx_out = priv->regs->tx_in; -+ priv->tx_tail = priv->regs->tx_in; -+ -+ return 0; -+} -+ -+/* -+ * ubi32_eth_set_config -+ */ -+static int ubi32_eth_set_config(struct net_device *dev, struct ifmap *map) -+{ -+ /* if must to down to config it */ -+ printk(KERN_INFO "set_config %x\n", dev->flags); -+ if (dev->flags & IFF_UP) -+ return -EBUSY; -+ -+ /* I/O and IRQ can not be changed */ -+ if (map->base_addr != dev->base_addr) { -+ printk(KERN_WARNING "%s: Can't change I/O address\n", dev->name); -+ return -EOPNOTSUPP; -+ } -+ -+#ifndef UBICOM32_USE_POLLING -+ if (map->irq != dev->irq) { -+ printk(KERN_WARNING "%s: Can't change IRQ\n", dev->name); -+ return -EOPNOTSUPP; -+ } -+#endif -+ -+ /* ignore other fields */ -+ return 0; -+} -+ -+static int ubi32_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ struct ubi32_eth_dma_desc *desc = NULL; -+ unsigned short space, tx_in; -+ -+ tx_in = priv->regs->tx_in; -+ -+ dev->trans_start = jiffies; /* save the timestamp */ -+ space = TX_DMA_RING_MASK - ((TX_DMA_RING_SIZE + tx_in - priv->tx_tail) & TX_DMA_RING_MASK); -+ -+ if (unlikely(space == 0)) { -+ if (!(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) { -+ spin_lock(&priv->lock); -+ if (!(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) { -+ priv->regs->status |= UBI32_ETH_VP_STATUS_TX_Q_FULL; -+ priv->vp_stats.tx_q_full_cnt++; -+ netif_stop_queue(dev); -+ } -+ spin_unlock(&priv->lock); -+ } -+ -+ /* give both HW and this driver an extra trigger */ -+ priv->regs->int_mask |= UBI32_ETH_VP_INT_TX; -+#ifndef UBICOM32_USE_POLLING -+ ubicom32_set_interrupt(dev->irq); -+#endif -+ ubicom32_set_interrupt(priv->vp_int_bit); -+ -+ return NETDEV_TX_BUSY; -+ } -+ -+ /*still have room */ -+ desc = (struct ubi32_eth_dma_desc *)skb->cb; -+ desc->data_pointer = skb->data; -+ desc->data_len = skb->len; -+ priv->regs->tx_dma_ring[tx_in] = desc; -+ tx_in = ((tx_in + 1) & TX_DMA_RING_MASK); -+ wmb(); -+ priv->regs->tx_in = tx_in; -+ /* kick the HRT */ -+ ubicom32_set_interrupt(priv->vp_int_bit); -+ -+ return NETDEV_TX_OK; -+} -+ -+/* -+ * Deal with a transmit timeout. -+ */ -+static void ubi32_eth_tx_timeout (struct net_device *dev) -+{ -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ dev->stats.tx_errors++; -+ priv->regs->int_mask |= UBI32_ETH_VP_INT_TX; -+#ifndef UBICOM32_USE_POLLING -+ ubicom32_set_interrupt(dev->irq); -+#endif -+ ubicom32_set_interrupt(priv->vp_int_bit); -+} -+ -+static int ubi32_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -+{ -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ struct mii_ioctl_data *data = if_mii(rq); -+ -+ printk(KERN_INFO "ioctl %s, %d\n", dev->name, cmd); -+ switch (cmd) { -+ case SIOCGMIIPHY: -+ data->phy_id = 0; -+ break; -+ -+ case SIOCGMIIREG: -+ if ((data->reg_num & 0x1F) == MII_BMCR) { -+ /* Make up MII control register value from what we know */ -+ data->val_out = 0x0000 -+ | ((priv->regs->status & UBI32_ETH_VP_STATUS_DUPLEX) -+ ? BMCR_FULLDPLX : 0) -+ | ((priv->regs->status & UBI32_ETH_VP_STATUS_SPEED100) -+ ? BMCR_SPEED100 : 0) -+ | ((priv->regs->status & UBI32_ETH_VP_STATUS_SPEED1000) -+ ? BMCR_SPEED1000 : 0); -+ } else if ((data->reg_num & 0x1F) == MII_BMSR) { -+ /* Make up MII status register value from what we know */ -+ data->val_out = -+ (BMSR_100FULL|BMSR_100HALF|BMSR_10FULL|BMSR_10HALF) -+ | ((priv->regs->status & UBI32_ETH_VP_STATUS_LINK) -+ ? BMSR_LSTATUS : 0); -+ } else { -+ return -EIO; -+ } -+ break; -+ -+ case SIOCSMIIREG: -+ return -EOPNOTSUPP; -+ break; -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Return statistics to the caller -+ */ -+static struct net_device_stats *ubi32_eth_get_stats(struct net_device *dev) -+{ -+ return &dev->stats; -+} -+ -+ -+static int ubi32_eth_change_mtu(struct net_device *dev, int new_mtu) -+{ -+ struct ubi32_eth_private *priv = netdev_priv(dev); -+ unsigned long flags; -+ -+ if ((new_mtu < 68) || (new_mtu > 1500)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ dev->mtu = new_mtu; -+ spin_unlock_irqrestore(&priv->lock, flags); -+ printk(KERN_INFO "set mtu to %d", new_mtu); -+ return 0; -+} -+ -+/* -+ * ubi32_eth_cleanup: unload the module -+ */ -+void ubi32_eth_cleanup(void) -+{ -+ struct ubi32_eth_private *priv; -+ struct net_device *dev; -+ int i; -+ -+ for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) { -+ dev = ubi32_eth_devices[i]; -+ if (dev) { -+ priv = netdev_priv(dev); -+ kfree(priv->regs->tx_dma_ring); -+ unregister_netdev(dev); -+ free_netdev(dev); -+ ubi32_eth_devices[i] = NULL; -+ } -+ } -+} -+ -+int ubi32_eth_init_module(void) -+{ -+ struct ethtionode *eth_node; -+ struct net_device *dev; -+ struct ubi32_eth_private *priv; -+ int i, err; -+ -+ /* -+ * Device allocation. -+ */ -+ err = 0; -+ for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) { -+ /* -+ * See if the eth_vp is in the device tree. -+ */ -+ eth_node = (struct ethtionode *)devtree_find_node(eth_if_name[i]); -+ if (!eth_node) { -+ printk(KERN_INFO "%s does not exist\n", eth_if_name[i]); -+ continue; -+ } -+ -+ eth_node->tx_dma_ring = (struct ubi32_eth_dma_desc **)kmalloc( -+ sizeof(struct ubi32_eth_dma_desc *) * -+ (TX_DMA_RING_SIZE + RX_DMA_RING_SIZE), -+ GFP_ATOMIC | __GFP_NOWARN | __GFP_NORETRY | GFP_DMA); -+ -+ if (eth_node->tx_dma_ring == NULL) { -+ eth_node->tx_dma_ring = (struct ubi32_eth_dma_desc **)kmalloc( -+ sizeof(struct ubi32_eth_dma_desc *) * -+ (TX_DMA_RING_SIZE + RX_DMA_RING_SIZE), GFP_KERNEL); -+ printk(KERN_INFO "fail to allocate from OCM\n"); -+ } -+ -+ if (!eth_node->tx_dma_ring) { -+ err = -ENOMEM; -+ break; -+ } -+ eth_node->rx_dma_ring = eth_node->tx_dma_ring + TX_DMA_RING_SIZE; -+ eth_node->tx_sz = TX_DMA_RING_SIZE - 1; -+ eth_node->rx_sz = RX_DMA_RING_SIZE - 1; -+ -+ dev = alloc_etherdev(sizeof(struct ubi32_eth_private)); -+ if (!dev) { -+ kfree(eth_node->tx_dma_ring); -+ err = -ENOMEM; -+ break; -+ } -+ priv = netdev_priv(dev); -+ priv->dev = dev; -+ -+ /* -+ * This just fill in some default Ubicom MAC address -+ */ -+ memcpy(dev->dev_addr, mac_addr[i], ETH_ALEN); -+ memset(dev->broadcast, 0xff, ETH_ALEN); -+ -+ priv->regs = eth_node; -+ priv->regs->command = 0; -+ priv->regs->int_mask = 0; -+ priv->regs->int_status = 0; -+ priv->regs->tx_out = 0; -+ priv->regs->rx_out = 0; -+ priv->regs->tx_in = 0; -+ priv->regs->rx_in = 0; -+ priv->rx_tail = 0; -+ priv->tx_tail = 0; -+ -+ priv->vp_int_bit = eth_node->dn.sendirq; -+ dev->irq = eth_node->dn.recvirq; -+ -+ spin_lock_init(&priv->lock); -+ -+ dev->open = ubi32_eth_open; -+ dev->stop = ubi32_eth_close; -+ dev->hard_start_xmit = ubi32_eth_start_xmit; -+ dev->tx_timeout = ubi32_eth_tx_timeout; -+ dev->watchdog_timeo = UBI32_ETH_VP_TX_TIMEOUT; -+ -+ dev->set_config = ubi32_eth_set_config; -+ dev->do_ioctl = ubi32_eth_ioctl; -+ dev->get_stats = ubi32_eth_get_stats; -+ dev->change_mtu = ubi32_eth_change_mtu; -+#ifdef UBICOM32_USE_NAPI -+ netif_napi_add(dev, &priv->napi, ubi32_eth_napi_poll, UBI32_ETH_NAPI_WEIGHT); -+#endif -+ err = register_netdev(dev); -+ if (err) { -+ printk(KERN_WARNING "Failed to register netdev %s\n", eth_if_name[i]); -+ //release_region(); -+ free_netdev(dev); -+ kfree(eth_node->tx_dma_ring); -+ break; -+ } -+ -+ ubi32_eth_devices[i] = dev; -+ printk(KERN_INFO "%s vp_base:0x%p, tio_int:%d irq:%d feature:0x%lx\n", -+ dev->name, priv->regs, eth_node->dn.sendirq, dev->irq, dev->features); -+ } -+ -+ if (err) { -+ ubi32_eth_cleanup(); -+ return err; -+ } -+ -+ if (!ubi32_eth_devices[0] && !ubi32_eth_devices[1]) { -+ return -ENODEV; -+ } -+ -+#if defined(UBICOM32_USE_POLLING) -+ init_timer(ð_poll_timer); -+ eth_poll_timer.function = ubi32_eth_poll; -+ eth_poll_timer.data = (unsigned long)0; -+ eth_poll_timer.expires = jiffies + 2; -+ add_timer(ð_poll_timer); -+#endif -+ -+ return 0; -+} -+ -+module_init(ubi32_eth_init_module); -+module_exit(ubi32_eth_cleanup); -+ -+MODULE_AUTHOR("Kan Yan, Greg Ren"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/drivers/net/ubi32-eth.h linux-2.6.30.10-ubi/drivers/net/ubi32-eth.h ---- linux-2.6.30.10/drivers/net/ubi32-eth.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/net/ubi32-eth.h 2009-12-11 11:45:18.000000000 +0200 -@@ -0,0 +1,132 @@ -+/* -+ * drivers/net/ubi32-eth.h -+ * Ubicom32 ethernet TIO interface driver definitions. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#ifndef _UBI32_ETH_H -+#define _UBI32_ETH_H -+ -+#include -+ -+#define UBI32_ETH_NUM_OF_DEVICES 2 -+ -+/* -+ * Number of bytes trashed beyond the packet data. -+ */ -+#define UBI32_ETH_TRASHED_MEMORY (CACHE_LINE_SIZE + ETH_HLEN - 1) -+ -+/* -+ * Linux already reserves NET_SKB_PAD bytes of headroom in each sk_buff. -+ * We want to be able to reserve at least one cache line to align Ethernet -+ * and IP header to cache line. -+ * Note that the TIO expects a CACHE_LINE_SIZE - ETH_HLEN aligned Ethernet -+ * header, while satisfies NET_IP_ALIGN (= 2) automatically. -+ * (NET_SKB_PAD is 16, NET_IP_ALIGN is 2, CACHE_LINE_SIZE is 32). -+ * You can add more space by making UBI32_ETH_RESERVE_EXTRA != 0. -+ */ -+#define UBI32_ETH_RESERVE_EXTRA (1 * CACHE_LINE_SIZE) -+#define UBI32_ETH_RESERVE_SPACE (UBI32_ETH_RESERVE_EXTRA + CACHE_LINE_SIZE) -+ -+struct ubi32_eth_dma_desc { -+ volatile void *data_pointer; /* pointer to the buffer */ -+ volatile u16 buffer_len; /* the buffer size */ -+ volatile u16 data_len; /* actual frame length */ -+ volatile u32 status; /* bit0: status to be update by VP; bit[31:1] time stamp */ -+}; -+ -+#define TX_DMA_RING_SIZE (1<<8) -+#define TX_DMA_RING_MASK (TX_DMA_RING_SIZE - 1) -+#define RX_DMA_RING_SIZE (1<<8) -+#define RX_DMA_RING_MASK (RX_DMA_RING_SIZE - 1) -+ -+#define RX_DMA_MAX_QUEUE_SIZE (RX_DMA_RING_SIZE - 1) /* no more than (RX_DMA_RING_SIZE - 1) */ -+#define RX_MAX_PKT_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN) -+#define RX_MIN_PKT_SIZE ETH_ZLEN -+#define RX_BUF_SIZE (RX_MAX_PKT_SIZE + VLAN_HLEN) /* allow double VLAN tag */ -+ -+#define UBI32_ETH_VP_TX_TIMEOUT (10*HZ) -+ -+struct ubi32_eth_vp_stats { -+ u32 rx_alloc_err; -+ u32 tx_q_full_cnt; -+ u32 rx_q_full_cnt; -+ u32 rx_throttle; -+}; -+ -+struct ubi32_eth_private { -+ struct net_device *dev; -+ struct ubi32_eth_vp_stats vp_stats; -+ spinlock_t lock; -+#ifdef UBICOM32_USE_NAPI -+ struct napi_struct napi; -+#else -+ struct tasklet_struct tsk; -+#endif -+ struct ethtionode *regs; -+ u16 rx_tail; -+ u16 tx_tail; -+ u32 vp_int_bit; -+}; -+ -+struct ethtionode { -+ struct devtree_node dn; -+ volatile u16 command; -+ volatile u16 status; -+ volatile u16 int_mask; /* interrupt mask */ -+ volatile u16 int_status; /* interrupt mask */ -+ volatile u16 tx_in; /* owned by driver */ -+ volatile u16 tx_out; /* owned by vp */ -+ volatile u16 rx_in; /* owned by driver */ -+ volatile u16 rx_out; /* owned by vp */ -+ u16 tx_sz; /* owned by driver */ -+ u16 rx_sz; /* owned by driver */ -+ struct ubi32_eth_dma_desc **tx_dma_ring; -+ struct ubi32_eth_dma_desc **rx_dma_ring; -+}; -+ -+#define UBI32_ETH_VP_STATUS_LINK (1<<0) -+#define UBI32_ETH_VP_STATUS_SPEED100 (0x1<<1) -+#define UBI32_ETH_VP_STATUS_SPEED1000 (0x1<<2) -+#define UBI32_ETH_VP_STATUS_DUPLEX (0x1<<3) -+#define UBI32_ETH_VP_STATUS_FLOW_CTRL (0x1<<4) -+ -+#define UBI32_ETH_VP_STATUS_RX_STATE (0x1<<5) -+#define UBI32_ETH_VP_STATUS_TX_STATE (0x1<<6) -+ -+#define UBI32_ETH_VP_STATUS_TX_Q_FULL (1<<8) -+ -+#define UBI32_ETH_VP_INT_RX (1<<0) -+#define UBI32_ETH_VP_INT_TX (1<<1) -+ -+#define UBI32_ETH_VP_CMD_RX_ENABLE (1<<0) -+#define UBI32_ETH_VP_CMD_TX_ENABLE (1<<1) -+ -+#define UBI32_ETH_VP_RX_OK (1<<0) -+#define UBI32_ETH_VP_TX_OK (1<<1) -+ -+#define UBI32_TX_BOUND TX_DMA_RING_SIZE -+#define UBI32_RX_BOUND 64 -+#define UBI32_ETH_NAPI_WEIGHT 64 /* for GigE */ -+#endif -diff -ruN linux-2.6.30.10/drivers/net/usb/asix.c linux-2.6.30.10-ubi/drivers/net/usb/asix.c ---- linux-2.6.30.10/drivers/net/usb/asix.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/net/usb/asix.c 2009-12-11 11:45:18.000000000 +0200 -@@ -319,14 +319,33 @@ +--- a/drivers/net/usb/asix.c ++++ b/drivers/net/usb/asix.c +@@ -319,14 +319,33 @@ static int asix_rx_fixup(struct usbnet * /* get the packet length */ size = (u16) (header & 0x0000ffff); @@ -46933,7 +198,7 @@ diff -ruN linux-2.6.30.10/drivers/net/usb/asix.c linux-2.6.30.10-ubi/drivers/net ax_skb->len = size; ax_skb->data = packet; skb_set_tail_pointer(ax_skb, size); -@@ -1125,13 +1144,19 @@ +@@ -1125,13 +1144,19 @@ static int ax88178_link_reset(struct usb mode = AX88178_MEDIUM_DEFAULT; if (ecmd.speed == SPEED_1000) @@ -46953,10 +218,9 @@ diff -ruN linux-2.6.30.10/drivers/net/usb/asix.c linux-2.6.30.10-ubi/drivers/net if (ecmd.duplex == DUPLEX_FULL) mode |= AX_MEDIUM_FD; -diff -ruN linux-2.6.30.10/drivers/oprofile/cpu_buffer.c linux-2.6.30.10-ubi/drivers/oprofile/cpu_buffer.c ---- linux-2.6.30.10/drivers/oprofile/cpu_buffer.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/oprofile/cpu_buffer.c 2009-12-11 11:45:18.000000000 +0200 -@@ -328,10 +328,10 @@ +--- a/drivers/oprofile/cpu_buffer.c ++++ b/drivers/oprofile/cpu_buffer.c +@@ -328,10 +328,10 @@ static inline void oprofile_end_trace(st } static inline void @@ -46970,7 +234,7 @@ diff -ruN linux-2.6.30.10/drivers/oprofile/cpu_buffer.c linux-2.6.30.10-ubi/driv unsigned long backtrace = oprofile_backtrace_depth; /* -@@ -353,7 +353,8 @@ +@@ -353,7 +353,8 @@ __oprofile_add_ext_sample(unsigned long void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, unsigned long event, int is_kernel) { @@ -46980,7 +244,7 @@ diff -ruN linux-2.6.30.10/drivers/oprofile/cpu_buffer.c linux-2.6.30.10-ubi/driv } void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) -@@ -361,7 +362,8 @@ +@@ -361,7 +362,8 @@ void oprofile_add_sample(struct pt_regs int is_kernel = !user_mode(regs); unsigned long pc = profile_pc(regs); @@ -46990,10 +254,9 @@ diff -ruN linux-2.6.30.10/drivers/oprofile/cpu_buffer.c linux-2.6.30.10-ubi/driv } /* -diff -ruN linux-2.6.30.10/drivers/pci/Makefile linux-2.6.30.10-ubi/drivers/pci/Makefile ---- linux-2.6.30.10/drivers/pci/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/pci/Makefile 2009-12-11 11:45:18.000000000 +0200 -@@ -44,8 +44,8 @@ +--- a/drivers/pci/Makefile ++++ b/drivers/pci/Makefile +@@ -44,8 +44,8 @@ obj-$(CONFIG_PPC) += setup-bus.o obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_MN10300) += setup-bus.o @@ -47003,10 +266,9 @@ diff -ruN linux-2.6.30.10/drivers/pci/Makefile linux-2.6.30.10-ubi/drivers/pci/M # ACPI Related PCI FW Functions # obj-$(CONFIG_ACPI) += pci-acpi.o -diff -ruN linux-2.6.30.10/drivers/serial/Kconfig linux-2.6.30.10-ubi/drivers/serial/Kconfig ---- linux-2.6.30.10/drivers/serial/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/serial/Kconfig 2009-12-11 11:45:19.000000000 +0200 -@@ -871,6 +871,57 @@ +--- a/drivers/serial/Kconfig ++++ b/drivers/serial/Kconfig +@@ -871,6 +871,57 @@ config SERIAL_UARTLITE_CONSOLE console (the system console is the device which receives all kernel messages and warnings and which allows logins in single user mode). @@ -47064,2949 +326,18 @@ diff -ruN linux-2.6.30.10/drivers/serial/Kconfig linux-2.6.30.10-ubi/drivers/ser config SERIAL_SUNCORE bool depends on SPARC -diff -ruN linux-2.6.30.10/drivers/serial/Makefile linux-2.6.30.10-ubi/drivers/serial/Makefile ---- linux-2.6.30.10/drivers/serial/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/serial/Makefile 2009-12-11 11:45:19.000000000 +0200 -@@ -77,3 +77,6 @@ +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -77,3 +77,6 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIA obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o +obj-$(CONFIG_SERIAL_UBI32_SERDES) += ubi32_serdes.o +obj-$(CONFIG_SERIAL_UBI32_UARTTIO) += ubi32_uarttio.o +obj-$(CONFIG_SERIAL_UBI32_MAILBOX) += ubi32_mailbox.o -diff -ruN linux-2.6.30.10/drivers/serial/ubi32_mailbox.c linux-2.6.30.10-ubi/drivers/serial/ubi32_mailbox.c ---- linux-2.6.30.10/drivers/serial/ubi32_mailbox.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/serial/ubi32_mailbox.c 2009-12-11 11:45:19.000000000 +0200 -@@ -0,0 +1,928 @@ -+/* -+ * drivers/serial/ubi32_mailbox.c -+ * Ubicom32 On-Chip Mailbox Driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define SERIAL_UBICOM_BAUDRATE 115200 -+#define SERIAL_UBICOM_DATA_BIT 8 /* Fixed parameter - do not change */ -+#define SERIAL_UBICOM_PAR_BIT 0 /* Fixed parameter - do not change */ -+#define SERIAL_UBICOM_STOP_BIT 1 /* Fixed parameter - do not change */ -+ -+/* UART name and device definitions */ -+#define UBI32_MAILBOX_NAME "ttyUM" // XXX -+#define UBI32_MAILBOX_MAJOR 207 // XXX -+#define UBI32_MAILBOX_MINOR 64 -+ -+#define PORT_UBI32_MAILBOX 1235 -+#define NR_PORTS 1 -+ -+#define get_sclk() 0 -+ -+struct ubi32_mailbox_port { -+ struct uart_port port; -+ /* -+ * NOTE (rkeller): -+ * the uart port is wrapped in another structure in case we need to hold more state than -+ * what we can hold in the uart_port. -+ * Not sure if we need this, I took over the concept from the blackfin driver. -+ */ -+} ubi32_mailbox_ports[NR_PORTS]; -+ -+struct ubi32_mailbox_resource { -+ int uart_base_addr; -+ int uart_irq; -+} ubi32_mailbox_resource[NR_PORTS] = { -+ /* -+ * uart_base_addr has to be non-NULL because it is put in the uart_port membase. -+ * If membase if null the kernel skips the configuration and our port_type never gets set. -+ */ -+ {ISD_MAILBOX_BASE, ISD_MAILBOX_INT} -+}; -+ -+static volatile struct ubicom32_isd_mailbox { -+ volatile u32_t in; -+ volatile u32_t out; -+ volatile u32_t status; -+} *ubi32_mailbox = (struct ubicom32_isd_mailbox *)ISD_MAILBOX_BASE; -+ -+static void ubi32_mailbox_tx_chars(struct ubi32_mailbox_port *uart); -+ -+static void ubi32_mailbox_mctrl_check(struct ubi32_mailbox_port *uart); -+ -+#define TRUE 1 -+#define FALSE 0 -+ -+static int mailbox_console_flg = TRUE; -+static int num_timeouts = 0; -+ -+/* -+ * dummy functions and defined to be able to compile the Blackfin code -+ */ -+#define UART_GET_LSR(port) (1) -+#define UART_PUT_LSR(port, bits) -+#define UART_CLEAR_LSR(port) (1) -+#define TEMT 1 -+#define TFI 1 -+#define BI 1 -+#define PE 1 -+#define OE 1 -+#define FE 1 -+#define THRE 1 -+#define DR 1 -+#define UART_GET_LCR(port) (1) -+#define UART_PUT_LCR(port, bits) -+#define SB 1 -+#define STB 1 -+#define PEN 1 -+#define EPS 1 -+#define STP 1 -+#define WLS(n) 0 -+#define UART_GET_IER(port) (1) -+#define UART_SET_IER(port, bits) -+#define UART_CLEAR_IER(port, bits) -+#define ETBEI 0 -+#define ERBFI 0 -+#define UART_GET_CHAR(port) ubi32_mailbox_get_char() -+#define UART_PUT_CHAR(port, ch) ubi32_mailbox_put_char(ch) -+#define SSYNC() -+#define UART_GET_DLL(port) 0 -+#define UART_PUT_DLL(port, ch) -+#define UART_GET_DLH(port) 0 -+#define UART_PUT_DLH(port, ch) -+#define UART_GET_GCTL(port) (0) -+#define UART_PUT_GCTL(port, ch) -+#define UCEN 1 -+ -+/* -+ * ubi32_mailbox_get_char_avail() -+ */ -+static int ubi32_mailbox_get_char_avail(void) -+{ -+ return !(ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY); -+} -+ -+/* -+ * ubi32_mailbox_get_char() -+ */ -+static u32_t ubi32_mailbox_get_char(void) -+{ -+ if (mailbox_console_flg == TRUE) { -+ /* -+ * Mailbox console is connected. -+ */ -+ while (ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY); -+ return ubi32_mailbox->in & 0xff; -+ } -+ -+ /* -+ * Mailbox console was not connected. -+ */ -+ if (ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY) { -+ return 0xff; -+ } -+ -+ /* -+ * Mailbox console is connecting. -+ */ -+ mailbox_console_flg = TRUE; -+ num_timeouts = 0; -+ return ubi32_mailbox->in & 0xff; -+} -+ -+#define MAILBOX_MAX_ATTEMPTS 1000000 -+#define MAILBOX_MAX_TIMEOUTS 5 -+/* -+ * ubi32_mailbox_put_char() -+ */ -+static void ubi32_mailbox_put_char(u32_t v) -+{ -+ /* -+ * Wait to be able to output. -+ */ -+ u32_t num_attempts = 0; -+ -+ if(mailbox_console_flg == TRUE) { -+ while(num_attempts++ < MAILBOX_MAX_ATTEMPTS) { -+ if(ubi32_mailbox->status & ISD_MAILBOX_STATUS_OUT_EMPTY) { -+ break; -+ } -+ } -+ -+ /* -+ * If timed out more than 5 times on send, mailbox console is disconnected now. -+ */ -+ if (num_attempts > MAILBOX_MAX_ATTEMPTS) { -+ if (num_timeouts++ > MAILBOX_MAX_TIMEOUTS) { -+ mailbox_console_flg = FALSE; -+ } -+ } -+ } -+ -+ asm volatile( -+ "pipe_flush 0 \n\t" -+ "pipe_flush 0 \n\t" -+ "pipe_flush 0 \n\t" -+ "pipe_flush 0 \n\t" -+ "pipe_flush 0 \n\t" -+ "pipe_flush 0 \n\t" -+ "pipe_flush 0 \n\t" -+ ); -+ -+ ubi32_mailbox->out = v & 0xff; -+} -+ -+static void ubi32_mailbox_hw_init(struct ubi32_mailbox_port *uart) -+{ -+// NOTE: It does not do any good to do these here because we are running on the linux hardware thread, -+// and these have to be called on the ldsr thread. -+// ubicom32_clear_interrupt(ISD_MAILBOX_INT); -+// ubicom32_enable_interrupt(ISD_MAILBOX_INT); -+} -+ -+/* -+ * interrupts are disabled on entry -+ */ -+static void ubi32_mailbox_stop_tx(struct uart_port *port) -+{ -+// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+// struct circ_buf *xmit = &uart->port.info->xmit; -+ -+ while (!(UART_GET_LSR(uart) & TEMT)) -+ cpu_relax(); -+ -+ /* Clear TFI bit */ -+ UART_PUT_LSR(uart, TFI); -+ UART_CLEAR_IER(uart, ETBEI); -+} -+ -+/* -+ * port is locked and interrupts are disabled -+ */ -+static void ubi32_mailbox_start_tx(struct uart_port *port) -+{ -+ struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ -+ UART_SET_IER(uart, ETBEI); -+ -+ ubi32_mailbox_tx_chars(uart); -+} -+ -+/* -+ * Interrupts are enabled -+ */ -+static void ubi32_mailbox_stop_rx(struct uart_port *port) -+{ -+// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ UART_CLEAR_IER(uart, ERBFI); -+} -+ -+/* -+ * Set the modem control timer to fire immediately. -+ */ -+static void ubi32_mailbox_enable_ms(struct uart_port *port) -+{ -+} -+ -+static void ubi32_mailbox_rx_chars(struct ubi32_mailbox_port *uart) -+{ -+ struct uart_info *info = uart->port.info; -+ struct tty_struct *tty = info->port.tty; -+ unsigned int status, ch, flg; -+ -+ status = 0; // XXX? UART_GET_LSR(uart); -+ UART_CLEAR_LSR(uart); -+ -+ ch = UART_GET_CHAR(uart); -+ -+ if(ch == 0xff) -+ return; -+ -+ uart->port.icount.rx++; -+ -+ if (status & BI) { -+ uart->port.icount.brk++; -+ if (uart_handle_break(&uart->port)) -+ goto ignore_char; -+ status &= ~(PE | FE); -+ } -+ if (status & PE) -+ uart->port.icount.parity++; -+ if (status & OE) -+ uart->port.icount.overrun++; -+ if (status & FE) -+ uart->port.icount.frame++; -+ -+ status &= uart->port.read_status_mask; -+ -+ if (status & BI) -+ flg = TTY_BREAK; -+ else if (status & PE) -+ flg = TTY_PARITY; -+ else if (status & FE) -+ flg = TTY_FRAME; -+ else -+ flg = TTY_NORMAL; -+ -+ if (uart_handle_sysrq_char(&uart->port, ch)) -+ goto ignore_char; -+ -+ uart_insert_char(&uart->port, status, OE, ch, flg); -+ -+ ignore_char: -+ tty_flip_buffer_push(tty); -+} -+ -+static void ubi32_mailbox_tx_chars(struct ubi32_mailbox_port *uart) -+{ -+ struct circ_buf *xmit = &uart->port.info->xmit; -+ -+ if (uart->port.x_char) { -+ UART_PUT_CHAR(uart, uart->port.x_char); -+ uart->port.icount.tx++; -+ uart->port.x_char = 0; -+ } -+ /* -+ * Check the modem control lines before -+ * transmitting anything. -+ */ -+ ubi32_mailbox_mctrl_check(uart); -+ -+ if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { -+ ubi32_mailbox_stop_tx(&uart->port); -+ return; -+ } -+ -+ while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) { -+ UART_PUT_CHAR(uart, xmit->buf[xmit->tail]); -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -+ uart->port.icount.tx++; -+ SSYNC(); -+ } -+ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(&uart->port); -+ -+ if (uart_circ_empty(xmit)) -+ ubi32_mailbox_stop_tx(&uart->port); -+} -+ -+static irqreturn_t ubi32_mailbox_isr(int irq, void *dev_id) -+{ -+ struct ubi32_mailbox_port *uart = dev_id; -+ -+ spin_lock(&uart->port.lock); -+ -+ //XXX?while (UART_GET_LSR(uart) & DR) -+ -+ /* -+ * RX process -+ */ -+ while (ubi32_mailbox_get_char_avail()) { -+ ubi32_mailbox_rx_chars(uart); -+ } -+ -+#if 0 -+ /* -+ * TX process -+ */ -+ if (this_uart.tx_in == this_uart.tx_out) { -+ UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_mask &= ~IO_PORTX_INT_SERDES_TXBE; -+ } else if (UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_status & IO_PORTX_INT_SERDES_TXBE) { -+ uart_ubicom32_send(this_uart.tx_buf[this_uart.tx_out & (SERIAL_UBICOM_BUF_SIZE - 1)]); -+ this_uart.tx_out++; -+ UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_mask |= IO_PORTX_INT_SERDES_TXBE; -+ } -+#endif -+ -+ spin_unlock(&uart->port.lock); -+ -+ return IRQ_HANDLED; -+} -+#if 0 -+static irqreturn_t ubi32_mailbox_tx_int(int irq, void *dev_id) -+{ -+ struct ubi32_mailbox_port *uart = dev_id; -+ -+ spin_lock(&uart->port.lock); -+ if (UART_GET_LSR(uart) & THRE) -+ ubi32_mailbox_tx_chars(uart); -+ spin_unlock(&uart->port.lock); -+ -+ return IRQ_HANDLED; -+} -+#endif -+ -+/* -+ * Return TIOCSER_TEMT when transmitter is not busy. -+ */ -+static unsigned int ubi32_mailbox_tx_empty(struct uart_port *port) -+{ -+// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ unsigned short lsr; -+ -+ lsr = UART_GET_LSR(uart); -+ if (lsr & TEMT) -+ return TIOCSER_TEMT; -+ else -+ return 0; -+} -+ -+static unsigned int ubi32_mailbox_get_mctrl(struct uart_port *port) -+{ -+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -+} -+ -+static void ubi32_mailbox_set_mctrl(struct uart_port *port, unsigned int mctrl) -+{ -+} -+ -+/* -+ * Handle any change of modem status signal since we were last called. -+ */ -+static void ubi32_mailbox_mctrl_check(struct ubi32_mailbox_port *uart) -+{ -+} -+ -+/* -+ * Interrupts are always disabled. -+ */ -+static void ubi32_mailbox_break_ctl(struct uart_port *port, int break_state) -+{ -+// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ u16 lcr = UART_GET_LCR(uart); -+ if (break_state) -+ lcr |= SB; -+ else -+ lcr &= ~SB; -+ UART_PUT_LCR(uart, lcr); -+ SSYNC(); -+} -+ -+static int ubi32_mailbox_startup(struct uart_port *port) -+{ -+ struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ -+ if (request_irq(uart->port.irq, ubi32_mailbox_isr, IRQF_DISABLED, -+ "UBI32_MAILBOX", uart)) { -+ printk(KERN_NOTICE "Unable to attach Ubicom32 SERDES interrupt\n"); -+ return -EBUSY; -+ } -+ -+ UART_SET_IER(uart, ERBFI); -+ return 0; -+} -+ -+static void ubi32_mailbox_shutdown(struct uart_port *port) -+{ -+ struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ -+ free_irq(uart->port.irq, uart); -+} -+ -+static void -+ubi32_mailbox_set_termios(struct uart_port *port, struct ktermios *termios, -+ struct ktermios *old) -+{ -+ struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ unsigned long flags; -+ unsigned int baud, quot; -+ unsigned short val, ier, lsr, lcr = 0; -+ -+ switch (termios->c_cflag & CSIZE) { -+ case CS8: -+ lcr = WLS(8); -+ break; -+ case CS7: -+ lcr = WLS(7); -+ break; -+ case CS6: -+ lcr = WLS(6); -+ break; -+ case CS5: -+ lcr = WLS(5); -+ break; -+ default: -+ printk(KERN_ERR "%s: word lengh not supported\n", -+ __FUNCTION__); -+ } -+ -+ if (termios->c_cflag & CSTOPB) -+ lcr |= STB; -+ if (termios->c_cflag & PARENB) -+ lcr |= PEN; -+ if (!(termios->c_cflag & PARODD)) -+ lcr |= EPS; -+ if (termios->c_cflag & CMSPAR) -+ lcr |= STP; -+ -+ port->read_status_mask = OE; -+ if (termios->c_iflag & INPCK) -+ port->read_status_mask |= (FE | PE); -+ if (termios->c_iflag & (BRKINT | PARMRK)) -+ port->read_status_mask |= BI; -+ -+ /* -+ * Characters to ignore -+ */ -+ port->ignore_status_mask = 0; -+ if (termios->c_iflag & IGNPAR) -+ port->ignore_status_mask |= FE | PE; -+ if (termios->c_iflag & IGNBRK) { -+ port->ignore_status_mask |= BI; -+ /* -+ * If we're ignoring parity and break indicators, -+ * ignore overruns too (for real raw support). -+ */ -+ if (termios->c_iflag & IGNPAR) -+ port->ignore_status_mask |= OE; -+ } -+ -+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); -+ quot = uart_get_divisor(port, baud); -+ spin_lock_irqsave(&uart->port.lock, flags); -+ -+ do { -+ lsr = UART_GET_LSR(uart); -+ } while (!(lsr & TEMT)); -+ -+ /* Disable UART */ -+ ier = UART_GET_IER(uart); -+ UART_CLEAR_IER(uart, 0xF); -+ -+ UART_PUT_DLL(uart, quot & 0xFF); -+ SSYNC(); -+ UART_PUT_DLH(uart, (quot >> 8) & 0xFF); -+ SSYNC(); -+ -+ UART_PUT_LCR(uart, lcr); -+ -+ /* Enable UART */ -+ UART_SET_IER(uart, ier); -+ -+ val = UART_GET_GCTL(uart); -+ val |= UCEN; -+ UART_PUT_GCTL(uart, val); -+ -+ spin_unlock_irqrestore(&uart->port.lock, flags); -+} -+ -+static const char *ubi32_mailbox_type(struct uart_port *port) -+{ -+ struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ -+ return uart->port.type == PORT_UBI32_MAILBOX ? "UBI32_MAILBOX" : NULL; -+} -+ -+/* -+ * Release the memory region(s) being used by 'port'. -+ */ -+static void ubi32_mailbox_release_port(struct uart_port *port) -+{ -+} -+ -+/* -+ * Request the memory region(s) being used by 'port'. -+ */ -+static int ubi32_mailbox_request_port(struct uart_port *port) -+{ -+ return 0; -+} -+ -+/* -+ * Configure/autoconfigure the port. -+ */ -+static void ubi32_mailbox_config_port(struct uart_port *port, int flags) -+{ -+ struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ -+ if (flags & UART_CONFIG_TYPE && ubi32_mailbox_request_port(&uart->port) == 0) -+ uart->port.type = PORT_UBI32_MAILBOX; -+} -+ -+/* -+ * Verify the new serial_struct (for TIOCSSERIAL). -+ * The only change we allow are to the flags and type, and -+ * even then only between PORT_UBI32_MAILBOX and PORT_UNKNOWN -+ */ -+static int -+ubi32_mailbox_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ return 0; -+} -+ -+static struct uart_ops ubi32_mailbox_pops = { -+ .tx_empty = ubi32_mailbox_tx_empty, -+ .set_mctrl = ubi32_mailbox_set_mctrl, -+ .get_mctrl = ubi32_mailbox_get_mctrl, -+ .stop_tx = ubi32_mailbox_stop_tx, -+ .start_tx = ubi32_mailbox_start_tx, -+ .stop_rx = ubi32_mailbox_stop_rx, -+ .enable_ms = ubi32_mailbox_enable_ms, -+ .break_ctl = ubi32_mailbox_break_ctl, -+ .startup = ubi32_mailbox_startup, -+ .shutdown = ubi32_mailbox_shutdown, -+ .set_termios = ubi32_mailbox_set_termios, -+ .type = ubi32_mailbox_type, -+ .release_port = ubi32_mailbox_release_port, -+ .request_port = ubi32_mailbox_request_port, -+ .config_port = ubi32_mailbox_config_port, -+ .verify_port = ubi32_mailbox_verify_port, -+}; -+ -+static void __init ubi32_mailbox_init_ports(void) -+{ -+ static int first = 1; -+ int i; -+ -+ if (!first) -+ return; -+ first = 0; -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ ubi32_mailbox_ports[i].port.uartclk = get_sclk(); -+ ubi32_mailbox_ports[i].port.ops = &ubi32_mailbox_pops; -+ ubi32_mailbox_ports[i].port.line = i; -+ ubi32_mailbox_ports[i].port.iotype = UPIO_MEM; -+ ubi32_mailbox_ports[i].port.membase = -+ (void __iomem *)ubi32_mailbox_resource[i].uart_base_addr; -+ ubi32_mailbox_ports[i].port.mapbase = -+ ubi32_mailbox_resource[i].uart_base_addr; -+ ubi32_mailbox_ports[i].port.irq = -+ ubi32_mailbox_resource[i].uart_irq; -+ ubi32_mailbox_ports[i].port.flags = UPF_BOOT_AUTOCONF; -+ spin_lock_init(&ubi32_mailbox_ports[i].port.lock); -+ -+ ubi32_mailbox_hw_init(&ubi32_mailbox_ports[i]); -+ } -+ -+} -+ -+#ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE -+/* -+ * If the port was already initialised (eg, by a boot loader), -+ * try to determine the current setup. -+ */ -+static void __init -+ubi32_mailbox_console_get_options(struct ubi32_mailbox_port *uart, int *baud, -+ int *parity, int *bits) -+{ -+ unsigned short status; -+ -+ status = UART_GET_IER(uart) & (ERBFI | ETBEI); -+ if (status == (ERBFI | ETBEI)) { -+ /* ok, the port was enabled */ -+ unsigned short lcr; -+ unsigned short dlh, dll; -+ -+ lcr = UART_GET_LCR(uart); -+ -+ *parity = 'n'; -+ if (lcr & PEN) { -+ if (lcr & EPS) -+ *parity = 'e'; -+ else -+ *parity = 'o'; -+ } -+ switch (lcr & 0x03) { -+ case 0: *bits = 5; break; -+ case 1: *bits = 6; break; -+ case 2: *bits = 7; break; -+ case 3: *bits = 8; break; -+ } -+ -+ dll = UART_GET_DLL(uart); -+ dlh = UART_GET_DLH(uart); -+ -+ *baud = get_sclk() / (16*(dll | dlh << 8)); -+ } -+ pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits); -+} -+#endif -+ -+#if defined(CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE) || defined(CONFIG_EARLY_PRINTK) -+static struct uart_driver ubi32_mailbox_reg; -+ -+static int __init -+ubi32_mailbox_console_setup(struct console *co, char *options) -+{ -+ struct ubi32_mailbox_port *uart; -+# ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE -+ int baud = SERIAL_UBICOM_BAUDRATE; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+# endif -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ if (co->index == -1 || co->index >= NR_PORTS) -+ co->index = 0; -+ uart = &ubi32_mailbox_ports[co->index]; -+ -+# ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ else -+ ubi32_mailbox_console_get_options(uart, &baud, &parity, &bits); -+ -+ //JB return uart_set_options(&uart->port, co, baud, parity, bits, flow); -+ return 0; -+# else -+ return 0; -+# endif -+} -+#endif /* defined (CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE) || -+ defined (CONFIG_EARLY_PRINTK) */ -+ -+#ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE -+static void ubi32_mailbox_console_putchar(struct uart_port *port, int ch) -+{ -+// struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port; -+ while (!(UART_GET_LSR(uart) & THRE)) -+ barrier(); -+ UART_PUT_CHAR(uart, ch); -+ SSYNC(); -+} -+ -+/* -+ * Interrupts are disabled on entering -+ */ -+static void -+ubi32_mailbox_console_write(struct console *co, const char *s, unsigned int count) -+{ -+ struct ubi32_mailbox_port *uart = &ubi32_mailbox_ports[co->index]; -+ unsigned long flags = 0; -+ -+ spin_lock_irqsave(&uart->port.lock, flags); -+ uart_console_write(&uart->port, s, count, ubi32_mailbox_console_putchar); -+ spin_unlock_irqrestore(&uart->port.lock, flags); -+ -+} -+ -+static struct console ubi32_mailbox_console = { -+ .name = UBI32_MAILBOX_NAME, -+ .write = ubi32_mailbox_console_write, -+ .device = uart_console_device, -+ .setup = ubi32_mailbox_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+ .data = &ubi32_mailbox_reg, -+}; -+ -+static int __init ubi32_mailbox_console_init(void) -+{ -+ ubi32_mailbox_init_ports(); -+ register_console(&ubi32_mailbox_console); -+ return 0; -+} -+console_initcall(ubi32_mailbox_console_init); -+ -+#define UBI32_MAILBOX_CONSOLE &ubi32_mailbox_console -+#else -+#define UBI32_MAILBOX_CONSOLE NULL -+#endif /* CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE */ -+ -+ -+#ifdef CONFIG_EARLY_PRINTK -+static __init void ubi32_mailbox_early_putc(struct uart_port *port, int ch) -+{ -+ UART_PUT_CHAR(uart, ch); -+} -+ -+static __init void ubi32_mailbox_early_write(struct console *con, const char *s, -+ unsigned int n) -+{ -+ struct ubi32_mailbox_port *uart = &ubi32_mailbox_ports[con->index]; -+ unsigned int i; -+ -+ for (i = 0; i < n; i++, s++) { -+ if (*s == '\n') -+ ubi32_mailbox_early_putc(&uart->port, '\r'); -+ ubi32_mailbox_early_putc(&uart->port, *s); -+ } -+} -+ -+static struct __init console ubi32_mailbox_early_console = { -+ .name = "early_UM", -+ .write = ubi32_mailbox_early_write, -+ .device = uart_console_device, -+ .flags = CON_PRINTBUFFER, -+ .setup = ubi32_mailbox_console_setup, -+ .index = -1, -+ .data = &ubi32_mailbox_reg, -+}; -+ -+/* -+ * XXX Unused in our driver. Need to find out what the termios initialization is good/needed for. -+ */ -+struct console __init *ubi32_mailbox_early_init(unsigned int port, -+ unsigned int cflag) -+{ -+ struct ubi32_mailbox_port *uart; -+ struct ktermios t; -+ -+ if (port == -1 || port >= NR_PORTS) -+ port = 0; -+ ubi32_mailbox_init_ports(); -+ ubi32_mailbox_early_console.index = port; -+ uart = &ubi32_mailbox_ports[port]; -+ t.c_cflag = cflag; -+ t.c_iflag = 0; -+ t.c_oflag = 0; -+ t.c_lflag = ICANON; -+ t.c_line = port; -+ ubi32_mailbox_set_termios(&uart->port, &t, &t); -+ return &ubi32_mailbox_early_console; -+} -+ -+#endif /* CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE */ -+ -+static struct uart_driver ubi32_mailbox_reg = { -+ .owner = THIS_MODULE, -+ .driver_name = "ubi32_mailbox", -+ .dev_name = UBI32_MAILBOX_NAME, -+ .major = UBI32_MAILBOX_MAJOR, -+ .minor = UBI32_MAILBOX_MINOR, -+ .nr = NR_PORTS, -+ .cons = UBI32_MAILBOX_CONSOLE, -+}; -+ -+static int ubi32_mailbox_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ struct ubi32_mailbox_port *uart = platform_get_drvdata(dev); -+ -+ if (uart) -+ uart_suspend_port(&ubi32_mailbox_reg, &uart->port); -+ -+ return 0; -+} -+ -+static int ubi32_mailbox_resume(struct platform_device *dev) -+{ -+ struct ubi32_mailbox_port *uart = platform_get_drvdata(dev); -+ -+ if (uart) -+ uart_resume_port(&ubi32_mailbox_reg, &uart->port); -+ -+ return 0; -+} -+ -+static int ubi32_mailbox_probe(struct platform_device *dev) -+{ -+ struct resource *res = dev->resource; -+ int i; -+ -+ for (i = 0; i < dev->num_resources; i++, res++) -+ if (res->flags & IORESOURCE_MEM) -+ break; -+ -+ if (i < dev->num_resources) { -+ for (i = 0; i < NR_PORTS; i++, res++) { -+ if (ubi32_mailbox_ports[i].port.mapbase != res->start) -+ continue; -+ ubi32_mailbox_ports[i].port.dev = &dev->dev; -+ uart_add_one_port(&ubi32_mailbox_reg, &ubi32_mailbox_ports[i].port); -+ platform_set_drvdata(dev, &ubi32_mailbox_ports[i]); -+ } -+ } -+ -+ return 0; -+} -+ -+static int ubi32_mailbox_remove(struct platform_device *pdev) -+{ -+ struct ubi32_mailbox_port *uart = platform_get_drvdata(pdev); -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ if (uart) -+ uart_remove_one_port(&ubi32_mailbox_reg, &uart->port); -+ -+ return 0; -+} -+ -+static struct platform_driver ubi32_mailbox_driver = { -+ .probe = ubi32_mailbox_probe, -+ .remove = ubi32_mailbox_remove, -+ .suspend = ubi32_mailbox_suspend, -+ .resume = ubi32_mailbox_resume, -+ .driver = { -+ .name = "ubi32-mbox", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init ubi32_mailbox_init(void) -+{ -+ int ret; -+ -+ pr_info("Serial: Ubicom32 mailbox serial driver.\n"); -+ -+ mailbox_console_flg = TRUE; -+ num_timeouts = 0; -+ ubi32_mailbox_init_ports(); -+ -+ ret = uart_register_driver(&ubi32_mailbox_reg); -+ if (ret == 0) { -+ ret = platform_driver_register(&ubi32_mailbox_driver); -+ if (ret) { -+ pr_debug("uart register failed\n"); -+ uart_unregister_driver(&ubi32_mailbox_reg); -+ } -+ } -+ -+ /* -+ * XXX HACK: currently probe does not get called, but the port needs to be added to work. -+ */ -+ uart_add_one_port(&ubi32_mailbox_reg, &ubi32_mailbox_ports[0].port); -+ return ret; -+} -+ -+static void __exit ubi32_mailbox_exit(void) -+{ -+ platform_driver_unregister(&ubi32_mailbox_driver); -+ uart_unregister_driver(&ubi32_mailbox_reg); -+} -+ -+module_init(ubi32_mailbox_init); -+module_exit(ubi32_mailbox_exit); -+ -+MODULE_ALIAS_CHARDEV_MAJOR(UBI32_MAILBOX_MAJOR); -+MODULE_ALIAS("platform:ubi32_mailbox"); -diff -ruN linux-2.6.30.10/drivers/serial/ubi32_serdes.c linux-2.6.30.10-ubi/drivers/serial/ubi32_serdes.c ---- linux-2.6.30.10/drivers/serial/ubi32_serdes.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/serial/ubi32_serdes.c 2009-12-11 11:45:19.000000000 +0200 -@@ -0,0 +1,817 @@ -+/* -+ * drivers/serial/ubi32_serdes.c -+ * Ubicom32 On-Chip Serial Driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+#define SERIAL_UBICOM_PIN_RXD (1 << 0) -+#define SERIAL_UBICOM_PIN_TXD (1 << 6) -+#define SERIAL_UBICOM_CTL0 0x8b300000 -+#define SERIAL_UBICOM_CTL1 0x00000009 -+ -+#define SERIAL_UBICOM_DATA_BIT 8 /* Fixed parameter - do not change */ -+#define SERIAL_UBICOM_PAR_BIT 0 /* Fixed parameter - do not change */ -+#define SERIAL_UBICOM_STOP_BIT 1 /* Fixed parameter - do not change */ -+ -+/* UART name and device definitions */ -+#define UBI32_SERDES_NAME "ttyUS" // XXX -+#define UBI32_SERDES_MAJOR 206 // XXX -+#define UBI32_SERDES_MINOR 64 // XXX -+ -+#define PORT_UBI32_SERDES 1234 -+#define NR_PORTS 1 -+ -+struct uart_port ubi32_serdes_ports[NR_PORTS]; -+ -+struct ubi32_serdes_resource { -+ void *uart_base_addr; -+ int uart_irq; -+ int uart_clock; -+} ubi32_serdes_resource[NR_PORTS] = { -+ /* -+ * Get params from kernel command line (required for early printk) -+ * or from platform resources. -+ */ -+ {0, 0, 0} -+}; -+ -+/* -+ * Can get overridden by 'serdes=' kernel command line. -+ */ -+static int ubi32_serdes_default_baud_rate = 115200; -+ -+ -+#define IO_PORT(port) ((struct ubicom32_io_port *)port->membase) -+#define IO_PORT_INT_STATUS(port) (IO_PORT(port)->int_status) -+#define IO_PORT_INT_MASK(port) (IO_PORT(port)->int_mask) -+#define IO_PORT_INT_CLR(port) (IO_PORT(port)->int_clr) -+ -+ -+/* -+ * ubi32_serdes_get_char() -+ */ -+static u8_t ubi32_serdes_get_char(struct ubicom32_io_port *io_port) -+{ -+ /* -+ * Read from hardware (forced 32-bit atomic read). -+ */ -+ u32_t data = 0; -+ -+ if ( io_port ) { -+ io_port->int_clr = IO_PORTX_INT_SERDES_RXBF; -+ asm volatile ( -+ "move.4 %0, %1 \n\t" -+ : "=r" (data) -+ : "m" (*(u32_t *)&(io_port->rx_fifo)) -+ ); -+ } -+ -+ return (u8_t)(data & 0x000000ff); -+} -+ -+/* -+ * ubi32_serdes_put_char() -+ */ -+static void ubi32_serdes_put_char(struct ubicom32_io_port *io_port, u8_t c) -+{ -+ u32_t data = 0x0000fe00 | (c << 1); -+ -+ if ( io_port ) { -+ /* -+ * Fixed data format: -+ * [LSB]1 start bit - 8 data bits - no parity - 1 stop bit[MSB] -+ */ -+ io_port->int_clr = IO_PORTX_INT_SERDES_TXBE; -+ io_port->ctl2 = data; -+ io_port->int_set = IO_PORTX_INT_SERDES_TXBUF_VALID; -+ } -+} -+ -+static void ubi32_serdes_hw_init(struct uart_port *port, int baud) -+{ -+ struct ubicom32_io_port *io_port = IO_PORT(port); -+ -+ if ( io_port ) { -+ /* -+ * Put port functions 1-4 into reset state. -+ * Function 0 (GPIO) does not need or have a reset bit. -+ * -+ * Select SERDES function for restart below. -+ */ -+ io_port->function = -+ IO_FUNC_FUNCTION_RESET(1) | IO_FUNC_FUNCTION_RESET(2) | -+ IO_FUNC_FUNCTION_RESET(3) | IO_FUNC_FUNCTION_RESET(4) | -+ IO_PORTX_FUNC_SERDES; -+ -+ /* -+ * Configure SERDES baudrate -+ */ -+ if ( baud == 0 ) { -+ baud = ubi32_serdes_default_baud_rate; -+ } -+ -+ io_port->ctl0 = -+ SERIAL_UBICOM_CTL0 | -+ ((port->uartclk / (16 * baud)) - 1); -+ -+ io_port->ctl1 = -+ SERIAL_UBICOM_CTL1; -+ -+ /* -+ * don't interrupt until startup and start_tx -+ */ -+ io_port->int_mask = 0; -+ -+ /* -+ * Set TXD pin output, RXD input and prevent GPIO -+ * override on the TXD & RXD pins -+ */ -+ io_port->gpio_ctl &= ~SERIAL_UBICOM_PIN_RXD; -+ io_port->gpio_ctl |= SERIAL_UBICOM_PIN_TXD; -+ io_port->gpio_mask &= ~(SERIAL_UBICOM_PIN_RXD | SERIAL_UBICOM_PIN_TXD); -+ -+ /* -+ * Restart (un-reset) the port's SERDES function. -+ */ -+ io_port->function &= ~(IO_FUNC_FUNCTION_RESET(IO_PORTX_FUNC_SERDES)); -+ } -+} -+ -+#define ULITE_STATUS_RXVALID IO_PORTX_INT_SERDES_RXBF -+#define ULITE_STATUS_OVERRUN 0 -+#define ULITE_STATUS_FRAME 0 -+#define ULITE_STATUS_PARITY 0 -+#define ULITE_STATUS_TXEMPTY IO_PORTX_INT_SERDES_TXBE -+#define ULITE_STATUS_TXFULL 0 -+ -+static int ubi32_serdes_receive(struct uart_port *port, int stat) -+{ -+ struct tty_struct *tty = port->info->port.tty; -+ unsigned char ch = 0; -+ char flag = TTY_NORMAL; -+ -+ if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN -+ | ULITE_STATUS_FRAME)) == 0) -+ return 0; -+ -+ /* stats */ -+ if (stat & ULITE_STATUS_RXVALID) { -+ port->icount.rx++; -+ ch = ubi32_serdes_get_char((struct ubicom32_io_port *)port->membase); -+ -+ if (stat & ULITE_STATUS_PARITY) -+ port->icount.parity++; -+ } -+ -+ if (stat & ULITE_STATUS_OVERRUN) -+ port->icount.overrun++; -+ -+ if (stat & ULITE_STATUS_FRAME) -+ port->icount.frame++; -+ -+ -+ /* drop byte with parity error if IGNPAR specificed */ -+ if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY) -+ stat &= ~ULITE_STATUS_RXVALID; -+ -+ stat &= port->read_status_mask; -+ -+ if (stat & ULITE_STATUS_PARITY) -+ flag = TTY_PARITY; -+ -+ stat &= ~port->ignore_status_mask; -+ -+ if (stat & ULITE_STATUS_RXVALID) -+ tty_insert_flip_char(tty, ch, flag); -+ -+ if (stat & ULITE_STATUS_FRAME) -+ tty_insert_flip_char(tty, 0, TTY_FRAME); -+ -+ if (stat & ULITE_STATUS_OVERRUN) -+ tty_insert_flip_char(tty, 0, TTY_OVERRUN); -+ -+ return 1; -+} -+ -+/* -+ * interrupts are disabled on entry -+ */ -+static void ubi32_serdes_stop_tx(struct uart_port *port) -+{ -+ IO_PORT_INT_MASK(port) = IO_PORT_INT_MASK(port) & ~IO_PORTX_INT_SERDES_TXBE; -+} -+ -+static int ubi32_serdes_transmit(struct uart_port *port, int stat) -+{ -+ struct circ_buf *xmit = &port->info->xmit; -+ -+ if (!(stat & IO_PORTX_INT_SERDES_TXBE)) -+ return 0; -+ -+ if (port->x_char) { -+ ubi32_serdes_put_char(IO_PORT(port), port->x_char); -+ port->x_char = 0; -+ port->icount.tx++; -+ return 1; -+ } -+ -+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -+ ubi32_serdes_stop_tx(port); -+ return 0; -+ } -+ -+ ubi32_serdes_put_char(IO_PORT(port), xmit->buf[xmit->tail]); -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); -+ port->icount.tx++; -+ -+ /* wake up */ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(port); -+ -+ if (uart_circ_empty(xmit)) -+ ubi32_serdes_stop_tx(port); -+ -+ return 1; -+} -+ -+/* -+ * port is locked and interrupts are disabled -+ */ -+static void ubi32_serdes_start_tx(struct uart_port *port) -+{ -+ IO_PORT_INT_MASK(port) = IO_PORT_INT_MASK(port) | IO_PORTX_INT_SERDES_TXBE; -+ ubi32_serdes_transmit(port, IO_PORT_INT_STATUS(port)); -+} -+ -+/* -+ * Interrupts are enabled -+ */ -+static void ubi32_serdes_stop_rx(struct uart_port *port) -+{ -+ /* don't forward any more data (like !CREAD) */ -+ port->ignore_status_mask = IO_PORTX_INT_SERDES_RXBF; -+} -+ -+/* -+ * Set the modem control timer to fire immediately. -+ */ -+static void ubi32_serdes_enable_ms(struct uart_port *port) -+{ -+ /* N/A */ -+} -+ -+static irqreturn_t ubi32_serdes_isr(int irq, void *dev_id) -+{ -+ struct uart_port *port = dev_id; -+ int busy; -+ -+ spin_lock(&port->lock); -+ -+ do { -+ int stat = IO_PORT_INT_STATUS(port); -+ busy = ubi32_serdes_receive(port, stat); -+ busy |= ubi32_serdes_transmit(port, stat); -+ } while (busy); -+ -+ tty_flip_buffer_push(port->info->port.tty); -+ -+ spin_unlock(&port->lock); -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Return TIOCSER_TEMT when transmitter is not busy. -+ */ -+static unsigned int ubi32_serdes_tx_empty(struct uart_port *port) -+{ -+ unsigned long flags; -+ unsigned int ret; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ ret = IO_PORT_INT_STATUS(port); -+ spin_unlock_irqrestore(&port->lock, flags); -+ -+ return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; -+} -+ -+static unsigned int ubi32_serdes_get_mctrl(struct uart_port *port) -+{ -+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -+} -+ -+static void ubi32_serdes_set_mctrl(struct uart_port *port, unsigned int mctrl) -+{ -+ /* N/A */ -+} -+ -+/* -+ * Interrupts are always disabled. -+ */ -+static void ubi32_serdes_break_ctl(struct uart_port *port, int break_state) -+{ -+ /* N/A */ -+} -+ -+static int ubi32_serdes_startup(struct uart_port *port) -+{ -+ if (request_irq(port->irq, ubi32_serdes_isr, IRQF_DISABLED, -+ "UBI32_SERDES", port)) { -+ printk(KERN_NOTICE "Unable to attach port interrupt\n"); -+ return -EBUSY; -+ } -+ -+ IO_PORT_INT_CLR(port) = IO_PORTX_INT_SERDES_RXBF; -+ IO_PORT_INT_MASK(port) = IO_PORTX_INT_SERDES_RXBF; -+ return 0; -+} -+ -+static void ubi32_serdes_shutdown(struct uart_port *port) -+{ -+ struct ubi32_serdes_port *uart = (struct ubi32_serdes_port *)port; -+ -+ IO_PORT_INT_MASK(port) = 0; -+ free_irq(port->irq, uart); -+} -+ -+static void -+ubi32_serdes_set_termios(struct uart_port *port, struct ktermios *termios, -+ struct ktermios *old) -+{ -+ unsigned long flags; -+ unsigned int baud; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ -+ port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN -+ | ULITE_STATUS_TXFULL; -+ -+ if (termios->c_iflag & INPCK) -+ port->read_status_mask |= -+ ULITE_STATUS_PARITY | ULITE_STATUS_FRAME; -+ -+ port->ignore_status_mask = 0; -+ if (termios->c_iflag & IGNPAR) -+ port->ignore_status_mask |= ULITE_STATUS_PARITY -+ | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; -+ -+ /* ignore all characters if CREAD is not set */ -+ if ((termios->c_cflag & CREAD) == 0) -+ port->ignore_status_mask |= -+ ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY -+ | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; -+ -+ /* update timeout */ -+ baud = uart_get_baud_rate(port, termios, old, 0, 460800); -+ uart_update_timeout(port, termios->c_cflag, baud); -+ -+ IO_PORT(port)->ctl0 = SERIAL_UBICOM_CTL0 | -+ ((port->uartclk / (16 * baud)) - 1); -+ -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static const char *ubi32_serdes_type(struct uart_port *port) -+{ -+ return port->type == PORT_UBI32_SERDES ? "UBI32_SERDES" : NULL; -+} -+ -+/* -+ * Release the memory region(s) being used by 'port'. -+ */ -+static void ubi32_serdes_release_port(struct uart_port *port) -+{ -+} -+ -+/* -+ * Request the memory region(s) being used by 'port'. -+ */ -+static int ubi32_serdes_request_port(struct uart_port *port) -+{ -+ return 0; -+} -+ -+/* -+ * Configure/autoconfigure the port. -+ */ -+static void ubi32_serdes_config_port(struct uart_port *port, int flags) -+{ -+ if (flags & UART_CONFIG_TYPE && -+ ubi32_serdes_request_port(port) == 0) -+ port->type = PORT_UBI32_SERDES; -+} -+ -+/* -+ * Verify the new serial_struct (for TIOCSSERIAL). -+ * The only change we allow are to the flags and type, and -+ * even then only between PORT_UBI32_SERDES and PORT_UNKNOWN -+ */ -+static int -+ubi32_serdes_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ return 0; -+} -+ -+static struct uart_ops ubi32_serdes_pops = { -+ .tx_empty = ubi32_serdes_tx_empty, -+ .set_mctrl = ubi32_serdes_set_mctrl, -+ .get_mctrl = ubi32_serdes_get_mctrl, -+ .stop_tx = ubi32_serdes_stop_tx, -+ .start_tx = ubi32_serdes_start_tx, -+ .stop_rx = ubi32_serdes_stop_rx, -+ .enable_ms = ubi32_serdes_enable_ms, -+ .break_ctl = ubi32_serdes_break_ctl, -+ .startup = ubi32_serdes_startup, -+ .shutdown = ubi32_serdes_shutdown, -+ .set_termios = ubi32_serdes_set_termios, -+ .type = ubi32_serdes_type, -+ .release_port = ubi32_serdes_release_port, -+ .request_port = ubi32_serdes_request_port, -+ .config_port = ubi32_serdes_config_port, -+ .verify_port = ubi32_serdes_verify_port, -+}; -+ -+static void __init ubi32_serdes_init_ports(void) -+{ -+ int i; -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ ubi32_serdes_ports[i].uartclk = ubi32_serdes_resource[i].uart_clock; -+ ubi32_serdes_ports[i].ops = &ubi32_serdes_pops; -+ ubi32_serdes_ports[i].line = i; -+ ubi32_serdes_ports[i].iotype = UPIO_MEM; -+ ubi32_serdes_ports[i].membase = -+ (void __iomem *)ubi32_serdes_resource[i].uart_base_addr; -+ ubi32_serdes_ports[i].mapbase = -+ (resource_size_t)ubi32_serdes_resource[i].uart_base_addr; -+ ubi32_serdes_ports[i].irq = -+ ubi32_serdes_resource[i].uart_irq; -+ ubi32_serdes_ports[i].flags = UPF_BOOT_AUTOCONF; -+ -+ ubi32_serdes_hw_init(&ubi32_serdes_ports[i], 0); -+ } -+ -+} -+ -+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE -+/* -+ * If the port was already initialised (eg, by a boot loader), -+ * try to determine the current setup. -+ */ -+static void __init -+ubi32_serdes_console_get_options(struct uart_port *port, int *baud) -+{ -+ u32 round_to = 1200; -+ u32 real_baud; -+ -+ /* -+ * We might get called before platform init and with no -+ * kernel command line options, so port might be NULL. -+ */ -+ *baud = ubi32_serdes_default_baud_rate;; -+ if ( IO_PORT(port) == 0 ) -+ return; -+ -+ real_baud = port->uartclk -+ / (16 * ((IO_PORT(port)->ctl0 & ~SERIAL_UBICOM_CTL0) + 1)); -+ -+ *baud = ((real_baud + round_to - 1) / round_to) * round_to; -+ -+ pr_debug("%s:baud = %d, real_baud = %d\n", __FUNCTION__, *baud, real_baud); -+} -+#endif -+ -+#if defined(CONFIG_SERIAL_UBI32_SERDES_CONSOLE) || defined(CONFIG_EARLY_PRINTK) -+static struct uart_driver ubi32_serdes_reg; -+ -+static int __init -+ubi32_serdes_console_setup(struct console *co, char *options) -+{ -+ struct uart_port *port; -+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE -+ int baud = ubi32_serdes_default_baud_rate; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+#endif -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ if (co->index == -1 || co->index >= NR_PORTS) -+ co->index = 0; -+ port = &ubi32_serdes_ports[co->index]; -+ -+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE -+ if (options) { -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ ubi32_serdes_hw_init(port, baud); -+ } -+ else -+ ubi32_serdes_console_get_options(port, &baud); -+ -+ return uart_set_options(port, co, baud, parity, bits, flow); -+#else -+ return 0; -+#endif -+} -+#endif /* defined (CONFIG_SERIAL_UBI32_SERDES_CONSOLE) || -+ defined (CONFIG_EARLY_PRINTK) */ -+ -+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE -+static void -+ubi32_serdes_console_putchar(struct uart_port *port, int ch) -+{ -+ if ( IO_PORT(port) ) { -+ while (!(IO_PORT_INT_STATUS(port) & IO_PORTX_INT_SERDES_TXBE)) -+ barrier(); -+ ubi32_serdes_put_char(IO_PORT(port), ch); -+ } -+} -+ -+/* -+ * Interrupts are disabled on entering -+ */ -+static void -+ubi32_serdes_console_write(struct console *co, const char *s, unsigned int count) -+{ -+ struct uart_port *port = &ubi32_serdes_ports[co->index]; -+ unsigned long flags = 0; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ uart_console_write(port, s, count, ubi32_serdes_console_putchar); -+ spin_unlock_irqrestore(&port->lock, flags); -+ -+} -+ -+static struct console ubi32_serdes_console = { -+ .name = UBI32_SERDES_NAME, -+ .write = ubi32_serdes_console_write, -+ .device = uart_console_device, -+ .setup = ubi32_serdes_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+ .data = &ubi32_serdes_reg, -+}; -+ -+static int __init ubi32_serdes_console_init(void) -+{ -+ ubi32_serdes_init_ports(); -+ register_console(&ubi32_serdes_console); -+ return 0; -+} -+console_initcall(ubi32_serdes_console_init); -+ -+#define UBI32_SERDES_CONSOLE &ubi32_serdes_console -+#else -+#define UBI32_SERDES_CONSOLE NULL -+#endif /* CONFIG_SERIAL_UBI32_SERDES_CONSOLE */ -+ -+ -+#ifdef CONFIG_EARLY_PRINTK -+static __init void ubi32_serdes_early_putc(struct uart_port *port, int ch) -+{ -+ unsigned timeout = 0xffff; -+ -+ while ((!(IO_PORT_INT_STATUS(port) & IO_PORTX_INT_SERDES_TXBE)) && --timeout) -+ cpu_relax(); -+ ubi32_serdes_put_char(IO_PORT(port), ch); -+} -+ -+static __init void ubi32_serdes_early_write(struct console *con, const char *s, -+ unsigned int n) -+{ -+ struct uart_port *port = &ubi32_serdes_ports[con->index]; -+ unsigned int i; -+ -+ for (i = 0; i < n; i++, s++) { -+ if (*s == '\n') -+ ubi32_serdes_early_putc(port, '\r'); -+ ubi32_serdes_early_putc(port, *s); -+ } -+} -+ -+static struct __init console ubi32_serdes_early_console = { -+ .name = "early_US", -+ .write = ubi32_serdes_early_write, -+ .device = uart_console_device, -+ .flags = CON_PRINTBUFFER, -+ .setup = ubi32_serdes_console_setup, -+ .index = -1, -+ .data = &ubi32_serdes_reg, -+}; -+ -+/* -+ * XXX Unused in our driver. Need to find out what the termios initialization is good/needed for. -+ */ -+struct console __init *ubi32_serdes_early_init(unsigned int port_index, -+ unsigned int cflag) -+{ -+ struct uart_port *uart; -+ struct ktermios t; -+ -+ if (port_index == -1 || port_index >= NR_PORTS) -+ port_index = 0; -+ ubi32_serdes_init_ports(); -+ ubi32_serdes_early_console.index = port_index; -+ uart = &ubi32_serdes_ports[port_index]; -+ t.c_cflag = cflag; -+ t.c_iflag = 0; -+ t.c_oflag = 0; -+ t.c_lflag = ICANON; -+ t.c_line = port_index; -+ ubi32_serdes_set_termios(uart, &t, &t); -+ return &ubi32_serdes_early_console; -+} -+ -+#endif /* CONFIG_SERIAL_UBI32_SERDES_CONSOLE */ -+ -+static struct uart_driver ubi32_serdes_reg = { -+ .owner = THIS_MODULE, -+ .driver_name = "ubi32_serdes", -+ .dev_name = UBI32_SERDES_NAME, -+ .major = UBI32_SERDES_MAJOR, -+ .minor = UBI32_SERDES_MINOR, -+ .nr = NR_PORTS, -+ .cons = UBI32_SERDES_CONSOLE, -+}; -+ -+static int ubi32_serdes_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ struct uart_port *port = platform_get_drvdata(dev); -+ -+ if (port) -+ uart_suspend_port(&ubi32_serdes_reg, port); -+ -+ return 0; -+} -+ -+static int ubi32_serdes_resume(struct platform_device *dev) -+{ -+ struct uart_port *port = platform_get_drvdata(dev); -+ -+ if (port) -+ uart_resume_port(&ubi32_serdes_reg, port); -+ -+ return 0; -+} -+ -+static int ubi32_serdes_probe(struct platform_device *dev) -+{ -+ struct resource *res = dev->resource; -+ int i; -+ -+ for (i = 0; i < dev->num_resources; i++, res++) { -+ if (res->flags & IORESOURCE_MEM) { -+ ubi32_serdes_resource[0].uart_base_addr = (void *) res->start; -+ } -+ else if (res->flags & IORESOURCE_IRQ) { -+ ubi32_serdes_resource[0].uart_irq = res->start; -+ } -+ else if (res->flags & UBICOM32_SUART_IORESOURCE_CLOCK) { -+ ubi32_serdes_resource[0].uart_clock = res->start; -+ } -+ } -+ -+ ubi32_serdes_init_ports(); -+ -+ return 0; -+} -+ -+static int ubi32_serdes_remove(struct platform_device *pdev) -+{ -+ struct uart_port *port = platform_get_drvdata(pdev); -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ if (port) -+ uart_remove_one_port(&ubi32_serdes_reg, port); -+ -+ return 0; -+} -+ -+static struct platform_driver ubi32_serdes_driver = { -+ .remove = ubi32_serdes_remove, -+ .suspend = ubi32_serdes_suspend, -+ .resume = ubi32_serdes_resume, -+ .driver = { -+ .name = "ubicom32suart", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+ -+#ifndef MODULE -+/* -+ * Called at boot time. -+ * -+ * You can specify IO base, IRQ, and clock for the serdes serial port -+ * using kernel command line "serdes=0xiobase,irq,clock". Values -+ * specified will be overwritten by platform device data, if present. -+ */ -+static int __init ubi32_serdes_setup(char *str) -+{ -+#define N_PARMS (4+1) -+ int ints[N_PARMS]; -+ int i; -+ -+ str = get_options(str, ARRAY_SIZE(ints), ints); -+ -+ for (i = 0; i < N_PARMS; i++) { -+ if (i < ints[0]) { -+ if (i == 0) { -+ ubi32_serdes_resource[0].uart_base_addr = (void *) ints[i+1]; -+ } -+ else if (i == 1) { -+ ubi32_serdes_resource[0].uart_irq = ints[i+1]; -+ } -+ else if (i == 2) { -+ ubi32_serdes_resource[0].uart_clock = ints[i+1]; -+ } -+ else if (i == 3) { -+ ubi32_serdes_default_baud_rate = ints[i+1]; -+ } -+ } -+ } -+ return 1; -+} -+ -+__setup("serdes=", ubi32_serdes_setup); -+#endif -+ -+static int __init ubi32_serdes_init(void) -+{ -+ int ret; -+ -+ pr_info("Serial: Ubicom32 serdes uart serial driver\n"); -+ -+ ret = platform_driver_probe(&ubi32_serdes_driver, ubi32_serdes_probe); -+ if (ret != 0) { -+ printk(KERN_INFO "serdes platform_driver_probe() failed: %d\n", ret); -+ return ret; -+ } -+ -+ ubi32_serdes_init_ports(); -+ -+ ret = uart_register_driver(&ubi32_serdes_reg); -+ if ( ret == 0 ) { -+ ret = uart_add_one_port(&ubi32_serdes_reg, &ubi32_serdes_ports[0]); -+ if ( ret != 0 ) { -+ uart_unregister_driver(&ubi32_serdes_reg); -+ } -+ } -+ -+ return ret; -+} -+ -+static void __exit ubi32_serdes_exit(void) -+{ -+ platform_driver_unregister(&ubi32_serdes_driver); -+ uart_unregister_driver(&ubi32_serdes_reg); -+} -+ -+module_init(ubi32_serdes_init); -+module_exit(ubi32_serdes_exit); -+ -+MODULE_AUTHOR("Rainer Keller "); -+MODULE_DESCRIPTION("Ubicom generic serial port driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS_CHARDEV_MAJOR(UBI32_SERDES_MAJOR); -+MODULE_ALIAS("platform:ubi32_serdes"); -diff -ruN linux-2.6.30.10/drivers/serial/ubi32_uarttio.c linux-2.6.30.10-ubi/drivers/serial/ubi32_uarttio.c ---- linux-2.6.30.10/drivers/serial/ubi32_uarttio.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/serial/ubi32_uarttio.c 2009-12-11 11:45:19.000000000 +0200 -@@ -0,0 +1,1172 @@ -+/* -+ * drivers/serial/ubi32_uarttio.c -+ * Ubicom32 Serial Virtual Peripherial Driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#define DRIVER_NAME "ubi32_uarttio" -+ -+/* -+ * For storing the module parameters. -+ */ -+#define UBI32_UARTTIO_MAX_PARAM_LEN 80 -+static char utio_ports_param[UBI32_UARTTIO_MAX_PARAM_LEN]; -+ -+/* -+ * UART name and device definitions -+ */ -+#define UBI32_UARTTIO_NAME "ttyUV" // XXX -+#define UBI32_UARTTIO_MAJOR 206 // XXX -+#define UBI32_UARTTIO_MINOR 64 // XXX -+ -+/* -+ * The following structures are allocated statically because the -+ * memory allocation subsystem is not initialized this early on -+ */ -+ -+/* -+ * Per port structure -+ */ -+struct ubi32_uarttio_port { -+ struct uarttio_uart *uart; -+ unsigned int tx_pin; -+ unsigned int rx_pin; -+ -+ struct uart_port port; -+ -+ u8_t added; -+ -+ /* -+ * If this value is set, the port has had its direction set already -+ */ -+ u8_t port_init; -+}; -+static struct ubi32_uarttio_port uarttio_ports[CONFIG_SERIAL_UBI32_UARTTIO_NR_UARTS]; -+ -+/* -+ * Number of ports currently initialized -+ */ -+static int uarttio_nports; -+ -+/* -+ * Per device structure -+ */ -+struct ubi32_uarttio_instance { -+ struct uarttio_regs *regs; -+ struct ubi32_uarttio_port *ports; -+ -+ u8_t irq_requested; -+ u8_t driver_registered; -+ u8_t irq; -+}; -+static struct ubi32_uarttio_instance uarttio_inst; -+ -+#ifdef CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE -+static struct console ubi32_uarttio_console; -+#define UBI32_UARTTIO_CONSOLE &ubi32_uarttio_console -+#else -+#define UBI32_UARTTIO_CONSOLE NULL -+#endif -+ -+static struct uart_driver ubi32_uarttio_uart_driver = { -+ .owner = THIS_MODULE, -+ .driver_name = DRIVER_NAME, -+ .dev_name = UBI32_UARTTIO_NAME, -+ .major = UBI32_UARTTIO_MAJOR, -+ .minor = UBI32_UARTTIO_MINOR, -+ .cons = UBI32_UARTTIO_CONSOLE, -+}; -+ -+#ifdef UBI32_UARTTIO_UNUSED -+/* -+ * ubi32_uarttio_get_send_space -+ */ -+static int ubi32_uarttio_get_send_space(struct uarttio_uart *uart) -+{ -+ int count = uart->tx_fifo_head - uart->tx_fifo_tail; -+ if (count < 0) { -+ count += uart->tx_fifo_size; -+ } -+ return uart->tx_fifo_size - count; -+} -+#endif -+ -+/* -+ * ubi32_uarttio_get_recv_ready -+ */ -+static int ubi32_uarttio_get_recv_ready(struct uarttio_uart *uart) -+{ -+ int count = uart->rx_fifo_head - uart->rx_fifo_tail; -+ if (count < 0) { -+ count += uart->rx_fifo_size; -+ } -+ return count; -+} -+ -+/* -+ * ubi32_uarttio_get_char() -+ */ -+static u8_t ubi32_uarttio_get_char(struct uarttio_uart *uart) -+{ -+ /* -+ * Retrieve byte -+ */ -+ u32_t tail = uart->rx_fifo_tail; -+ u8_t data = uart->rx_fifo[tail]; -+ -+ if (++tail == uart->rx_fifo_size) { -+ tail = 0; -+ } -+ uart->rx_fifo_tail = tail; -+ -+ return data; -+} -+ -+/* -+ * ubi32_uarttio_put_char() -+ */ -+static int ubi32_uarttio_put_char(struct uarttio_uart *uart, u8_t c) -+{ -+ u32_t head = uart->tx_fifo_head; -+ u32_t prev = head; -+ -+ /* -+ * Wrap -+ */ -+ if (++head == uart->tx_fifo_size) { -+ head = 0; -+ } -+ -+ /* -+ * If there isn't any space, return EBUSY -+ */ -+ if (head == uart->tx_fifo_tail) { -+ return -EBUSY; -+ } -+ -+ /* -+ * Put the character in the queue -+ */ -+ uart->tx_fifo[prev] = c; -+ uart->tx_fifo_head = head; -+ -+ return 0; -+} -+ -+/* -+ * ubi32_uarttio_set_baud -+ */ -+static int ubi32_uarttio_set_baud(struct ubi32_uarttio_port *uup, unsigned int baud) -+{ -+ if (uup->uart->current_baud_rate == baud) { -+ return 0; -+ } -+ -+ uup->uart->baud_rate = baud; -+ uup->uart->flags |= UARTTIO_UART_FLAG_SET_RATE; -+ while (uup->uart->flags & UARTTIO_UART_FLAG_SET_RATE) { -+ cpu_relax(); -+ } -+ -+ if (uup->uart->current_baud_rate != baud) { -+ /* -+ * Failed to set baud rate -+ */ -+ printk(KERN_WARNING "Invalid baud rate %u, running at %u\n", baud, uup->uart->current_baud_rate); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* -+ * ubi32_uarttio_handle_receive -+ */ -+static void ubi32_uarttio_handle_receive(struct ubi32_uarttio_port *uup, int stat) -+{ -+ struct uarttio_uart *uart = uup->uart; -+ struct uart_port *port = &uup->port; -+ struct tty_struct *tty = port->info->port.tty; -+ unsigned char ch = 0; -+ char flag = TTY_NORMAL; -+ int count; -+ -+ if ((stat & (UARTTIO_UART_INT_RX | UARTTIO_UART_INT_RXFRAME | UARTTIO_UART_INT_RXOVF)) == 0) { -+ return; -+ } -+ -+ if (stat & UARTTIO_UART_INT_RX) { -+ count = ubi32_uarttio_get_recv_ready(uart); -+ port->icount.rx += count; -+ } -+ -+ if (stat & UARTTIO_UART_INT_RXOVF) { -+ port->icount.overrun++; -+ } -+ -+ if (stat & UARTTIO_UART_INT_RXFRAME) { -+ port->icount.frame++; -+ } -+ -+ stat &= ~port->ignore_status_mask; -+ -+ if (stat & UARTTIO_UART_INT_RX) { -+ int i; -+ for (i = 0; i < count; i++) { -+ ch = ubi32_uarttio_get_char(uart); -+ tty_insert_flip_char(tty, ch, flag); -+ } -+ } -+ -+ if (stat & UARTTIO_UART_INT_RXFRAME) { -+ tty_insert_flip_char(tty, 0, TTY_FRAME); -+ } -+ -+ if (stat & UARTTIO_UART_INT_RXOVF) { -+ tty_insert_flip_char(tty, 0, TTY_OVERRUN); -+ } -+} -+ -+/* -+ * ubi32_uarttio_stop_tx -+ * interrupts are disabled on entry -+ */ -+static void ubi32_uarttio_stop_tx(struct uart_port *port) -+{ -+ struct ubi32_uarttio_port *uup = port->private_data; -+ -+ uup->uart->int_mask &= ~UARTTIO_UART_INT_TXBE; -+} -+ -+/* -+ * ubi32_uarttio_handle_transmit -+ */ -+static void ubi32_uarttio_handle_transmit(struct ubi32_uarttio_port *uup, int stat) -+{ -+ struct uarttio_uart *uart = uup->uart; -+ struct uart_port *port = &uup->port; -+ struct circ_buf *xmit = &port->info->xmit; -+ -+ if (!(stat & UARTTIO_UART_INT_TXBE)) { -+ return; -+ } -+ -+ if (port->x_char) { -+ if (ubi32_uarttio_put_char(uart, port->x_char)) { -+ return; -+ } -+ port->x_char = 0; -+ port->icount.tx++; -+ return; -+ } -+ -+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -+ ubi32_uarttio_stop_tx(port); -+ return; -+ } -+ -+ /* -+ * Send as many characters as we can -+ */ -+ while (ubi32_uarttio_put_char(uart, xmit->buf[xmit->tail]) == 0) { -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -+ port->icount.tx++; -+ if (uart_circ_empty(xmit)) { -+ break; -+ } -+ } -+ -+ /* wake up */ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { -+ uart_write_wakeup(port); -+ } -+ -+ if (uart_circ_empty(xmit)) { -+ ubi32_uarttio_stop_tx(port); -+ } -+} -+ -+/* -+ * ubi32_uarttio_start_tx -+ * port is locked and interrupts are disabled -+ */ -+static void ubi32_uarttio_start_tx(struct uart_port *port) -+{ -+ struct ubi32_uarttio_port *uup = port->private_data; -+ struct uarttio_uart *uart = uup->uart; -+ -+ uart->int_mask |= UARTTIO_UART_INT_TXBE; -+} -+ -+/* -+ * ubi32_uarttio_stop_rx -+ * Interrupts are enabled -+ */ -+static void ubi32_uarttio_stop_rx(struct uart_port *port) -+{ -+ struct ubi32_uarttio_port *uup = port->private_data; -+ struct uarttio_uart *uart = uup->uart; -+ -+ /* -+ * don't forward any more data (like !CREAD) -+ */ -+ uart->int_mask &= ~UARTTIO_UART_INT_RX; -+ port->ignore_status_mask = UARTTIO_UART_INT_RX; -+} -+ -+/* -+ * ubi32_uarttio_enable_ms -+ * Set the modem control timer to fire immediately. -+ */ -+static void ubi32_uarttio_enable_ms(struct uart_port *port) -+{ -+ /* N/A */ -+} -+ -+/* -+ * ubi32_uarttio_isr -+ */ -+static irqreturn_t ubi32_uarttio_isr(int irq, void *appdata) -+{ -+ struct ubi32_uarttio_port *uup = uarttio_ports; -+ int i; -+ -+ /* -+ * Service all of the ports -+ */ -+ for (i = 0; i < uarttio_nports; i++) { -+ unsigned int flags; -+ -+ if (!(uup->uart->flags & UARTTIO_UART_FLAG_ENABLED)) { -+ uup++; -+ continue; -+ } -+ -+ spin_lock(&uup->port.lock); -+ -+ flags = uup->uart->int_flags; -+ -+ uup->uart->int_flags = 0; -+ -+ ubi32_uarttio_handle_receive(uup, flags); -+ ubi32_uarttio_handle_transmit(uup, flags); -+ -+ tty_flip_buffer_push(uup->port.info->port.tty); -+ -+ spin_unlock(&uup->port.lock); -+ -+ uup++; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * ubi32_uarttio_tx_empty -+ * Return TIOCSER_TEMT when transmitter is not busy. -+ */ -+static unsigned int ubi32_uarttio_tx_empty(struct uart_port *port) -+{ -+ struct ubi32_uarttio_port *uup = port->private_data; -+ -+ if (uup->uart->tx_fifo_head == uup->uart->tx_fifo_tail) { -+ return TIOCSER_TEMT; -+ } -+ -+ return 0; -+} -+ -+/* -+ * ubi32_uarttio_get_mctrl -+ */ -+static unsigned int ubi32_uarttio_get_mctrl(struct uart_port *port) -+{ -+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -+} -+ -+/* -+ * ubi32_uarttio_set_mctrl -+ */ -+static void ubi32_uarttio_set_mctrl(struct uart_port *port, unsigned int mctrl) -+{ -+ /* N/A */ -+} -+ -+/* -+ * ubi32_uarttio_break_ctl -+ */ -+static void ubi32_uarttio_break_ctl(struct uart_port *port, int break_state) -+{ -+ /* N/A */ -+} -+ -+/* -+ * ubi32_uarttio_startup -+ */ -+static int ubi32_uarttio_startup(struct uart_port *port) -+{ -+ struct ubi32_uarttio_port *uup = port->private_data; -+ struct uarttio_uart *uart = uup->uart; -+ -+ uart->flags |= UARTTIO_UART_FLAG_ENABLED; -+ -+ uart->int_mask |= UARTTIO_UART_INT_TXBE | UARTTIO_UART_INT_RX; -+ -+ return 0; -+} -+ -+/* -+ * ubi32_uarttio_shutdown -+ */ -+static void ubi32_uarttio_shutdown(struct uart_port *port) -+{ -+ struct ubi32_uarttio_port *uup = port->private_data; -+ struct uarttio_uart *uart = uup->uart; -+ -+ uart->int_mask = 0; -+ uart->flags &= ~UARTTIO_UART_FLAG_ENABLED; -+} -+ -+/* -+ * ubi32_uarttio_set_termios -+ */ -+static void ubi32_uarttio_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) -+{ -+ struct ubi32_uarttio_port *uup = port->private_data; -+ unsigned long flags; -+ unsigned int baud; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ -+#if 0 -+ port->read_status_mask = UBI32_UARTTIO_RX | UBI32_UARTTIO_RXOVF | UBI32_UARTTIO_TXOVF; -+ -+ if (termios->c_iflag & INPCK) { -+ port->read_status_mask |= UBI32_UARTTIO_RXFRAME; -+ } -+#endif -+ -+ port->ignore_status_mask = 0; -+ if (termios->c_iflag & IGNPAR) { -+ port->ignore_status_mask |= UARTTIO_UART_INT_RXFRAME | -+ UARTTIO_UART_INT_RXOVF; -+ } -+ -+ /* -+ * ignore all characters if CREAD is not set -+ */ -+ if ((termios->c_cflag & CREAD) == 0) { -+ port->ignore_status_mask |= UARTTIO_UART_INT_RX | -+ UARTTIO_UART_INT_RXFRAME | -+ UARTTIO_UART_INT_RXOVF; -+ } -+ -+ /* update timeout */ -+ baud = uart_get_baud_rate(port, termios, old, 0, 460800); -+ uart_update_timeout(port, termios->c_cflag, baud); -+ -+ ubi32_uarttio_set_baud(uup, baud); -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+/* -+ * ubi32_uarttio_type -+ */ -+static const char *ubi32_uarttio_type(struct uart_port *port) -+{ -+ return (port->type == PORT_UBI32_UARTTIO) ? "UBI32_UARTTIO" : NULL; -+} -+ -+/* -+ * ubi32_uarttio_release_port -+ * Release the memory region(s) being used by 'port'. -+ */ -+static void ubi32_uarttio_release_port(struct uart_port *port) -+{ -+} -+ -+/* -+ * ubi32_uarttio_request_port -+ * Request the memory region(s) being used by 'port'. -+ */ -+static int ubi32_uarttio_request_port(struct uart_port *port) -+{ -+ return 0; -+} -+ -+/* -+ * ubi32_uarttio_config_port -+ * Configure/autoconfigure the port. -+ */ -+static void ubi32_uarttio_config_port(struct uart_port *port, int flags) -+{ -+ if ((flags & UART_CONFIG_TYPE) && (ubi32_uarttio_request_port(port) == 0)) { -+ port->type = PORT_UBI32_UARTTIO; -+ } -+} -+ -+/* -+ * ubi32_uarttio_verify_port -+ * Verify the new serial_struct (for TIOCSSERIAL). -+ * -+ * The only change we allow are to the flags and type, and -+ * even then only between PORT_UBI32_UARTTIO and PORT_UNKNOWN -+ */ -+static int ubi32_uarttio_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ return 0; -+} -+ -+static struct uart_ops ubi32_uarttio_pops = { -+ .tx_empty = ubi32_uarttio_tx_empty, -+ .set_mctrl = ubi32_uarttio_set_mctrl, -+ .get_mctrl = ubi32_uarttio_get_mctrl, -+ .stop_tx = ubi32_uarttio_stop_tx, -+ .start_tx = ubi32_uarttio_start_tx, -+ .stop_rx = ubi32_uarttio_stop_rx, -+ .enable_ms = ubi32_uarttio_enable_ms, -+ .break_ctl = ubi32_uarttio_break_ctl, -+ .startup = ubi32_uarttio_startup, -+ .shutdown = ubi32_uarttio_shutdown, -+ .set_termios = ubi32_uarttio_set_termios, -+ .type = ubi32_uarttio_type, -+ .release_port = ubi32_uarttio_release_port, -+ .request_port = ubi32_uarttio_request_port, -+ .config_port = ubi32_uarttio_config_port, -+ .verify_port = ubi32_uarttio_verify_port, -+}; -+ -+/* -+ * ubi32_uarttio_add_ports -+ */ -+static int __init ubi32_uarttio_add_ports(void) -+{ -+ int res = 0; -+ struct ubi32_uarttio_port *uup = uarttio_ports; -+ int i = 0; -+ -+ for (i = 0; i < uarttio_nports; i++) { -+ /* -+ * Setup the GPIOs -+ */ -+ res = gpio_request(uup->tx_pin, "ubi32_uarttio_tx"); -+ if (res) { -+ printk(KERN_WARNING "Failed to request GPIO %d\n", uup->tx_pin); -+ res = -EBUSY; -+ goto next; -+ } -+ -+ res = gpio_request(uup->rx_pin, "ubi32_uarttio_rx"); -+ if (res) { -+ gpio_free(uup->tx_pin); -+ printk(KERN_WARNING "Failed to request GPIO %d\n", uup->rx_pin); -+ res = -EBUSY; -+ goto next; -+ } -+ -+ res = uart_add_one_port(&ubi32_uarttio_uart_driver, &uup->port); -+ if (res) { -+ gpio_free(uup->rx_pin); -+ gpio_free(uup->tx_pin); -+ res = -ENODEV; -+ printk(KERN_WARNING "Failed to add port %d,%d\n", uup->tx_pin, uup->rx_pin); -+ goto next; -+ } -+ uup->added = 1; -+ -+ /* -+ * Set the direction of the ports now, after we're sure that everything is ok -+ */ -+ if (!uup->port_init) { -+ gpio_direction_output(uup->tx_pin, 1); -+ gpio_direction_input(uup->rx_pin); -+ } -+ -+next: -+ uup++; -+ } -+ return res; -+} -+ -+/* -+ * ubi32_uarttio_cleanup -+ */ -+static void ubi32_uarttio_cleanup(void) -+{ -+ struct ubi32_uarttio_port *uup; -+ int i; -+ -+ /* -+ * Stop the hardware thread -+ */ -+ if (uarttio_inst.regs) { -+ thread_disable(uarttio_inst.regs->thread); -+ } -+ if (uarttio_inst.irq_requested) { -+ free_irq(uarttio_inst.irq, NULL); -+ } -+ -+ /* -+ * Get rid of the ports -+ */ -+ uup = uarttio_inst.ports; -+ for (i = 0; i < uarttio_nports; i++) { -+ gpio_free(uup->tx_pin); -+ gpio_free(uup->rx_pin); -+ if (uup->added) { -+ uart_remove_one_port(&ubi32_uarttio_uart_driver, &uup->port); -+ } -+ uup++; -+ } -+ -+ if (uarttio_inst.driver_registered) { -+ uart_unregister_driver(&ubi32_uarttio_uart_driver); -+ } -+} -+ -+/* -+ * ubi32_uarttio_setup_port -+ * Setup a port in the TIO registers -+ */ -+static int ubi32_uarttio_setup_port(int index, -+ struct uarttio_uart *uart, -+ unsigned int baud, unsigned int tx_pin, -+ unsigned int rx_pin) -+{ -+ struct ubi32_uarttio_port *uup = &uarttio_ports[index]; -+ void *tx_port = ubi_gpio_get_port(tx_pin); -+ void *rx_port = ubi_gpio_get_port(rx_pin); -+ -+ /* -+ * Verify the ports are on chip -+ */ -+ if (!tx_port || !rx_port) { -+ printk(KERN_WARNING "Invalid port(s) specified: %u or %u\n", tx_pin, rx_pin); -+ return -EINVAL; -+ } -+ -+ uup->tx_pin = tx_pin; -+ uup->rx_pin = rx_pin; -+ uup->uart = uart; -+ -+ /* -+ * Setup the port structure -+ */ -+ uup->port.ops = &ubi32_uarttio_pops; -+ uup->port.line = index; -+ uup->port.iotype = UPIO_MEM; -+ uup->port.flags = UPF_BOOT_AUTOCONF; -+ uup->port.fifosize = uup->uart->tx_fifo_size; -+ uup->port.private_data = uup; -+ -+ /* -+ * We share this IRQ across all ports -+ */ -+ uup->port.irq = uarttio_inst.irq; -+ -+ /* -+ * We really don't have a mem/map base but without these variables -+ * set, the serial_core won't startup. -+ */ -+ uup->port.membase = (void __iomem *)uup; -+ uup->port.mapbase = (resource_size_t)uup; -+ spin_lock_init(&uup->port.lock); -+ -+ /* -+ * Set up the hardware -+ */ -+ uart->flags = UARTTIO_UART_FLAG_SET_RATE | UARTTIO_UART_FLAG_RESET; -+ -+ uart->tx_port = (unsigned int)tx_port; -+ uart->tx_pin = gpio_pin_index(tx_pin); -+ uart->tx_bits = 8; -+ uart->tx_stop_bits = 1; -+ -+ uart->rx_port = (unsigned int)rx_port; -+ uart->rx_pin = gpio_pin_index(rx_pin); -+ uart->rx_bits = 8; -+ uart->rx_stop_bits = 1; -+ -+ uart->baud_rate = baud; -+ -+ return 0; -+} -+ -+enum ubi32_uarttio_parse_states { -+ UBI32_UARTTIO_PARSE_STATE_BAUD, -+ UBI32_UARTTIO_PARSE_STATE_TX_PIN, -+ UBI32_UARTTIO_PARSE_STATE_RX_PIN, -+ UBI32_UARTTIO_PARSE_STATE_HS, -+ UBI32_UARTTIO_PARSE_STATE_CTS_PIN, -+ UBI32_UARTTIO_PARSE_STATE_RTS_PIN, -+}; -+ -+/* -+ * ubi32_uarttio_parse_param -+ */ -+static int ubi32_uarttio_parse_param(char *str) -+{ -+ int res; -+ int i; -+ int baud = 0; -+ int tx_pin = 0; -+ int rx_pin = 0; -+ int hs = 0; -+ int cts_pin = 0; -+ int rts_pin = 0; -+ int nfound = 0; -+ enum ubi32_uarttio_parse_states state = UBI32_UARTTIO_PARSE_STATE_BAUD; -+ struct uarttio_uart *uart = uarttio_inst.regs->uarts; -+ -+ /* -+ * Run though the options and generate the proper structures -+ */ -+ res = get_option(&str, &i); -+ while ((res == 2) || (res == 1)) { -+ switch (state) { -+ case UBI32_UARTTIO_PARSE_STATE_BAUD: -+ /* -+ * If we are here and nfound > 0 then create the port -+ * based on the previous input -+ */ -+ if (nfound) { -+ /* -+ * Create the port -+ */ -+ if (ubi32_uarttio_setup_port(nfound - 1, uart, baud, tx_pin, rx_pin)) { -+ /* -+ * Port was invalid -+ */ -+ goto fail; -+ } else { -+ printk(KERN_INFO "Serial port %d: tx=%d:rx=%d @ %d\n", nfound, tx_pin, rx_pin, baud); -+ uart++; -+ } -+ } -+ -+ /* -+ * Reset the variables and go to the next state -+ */ -+ hs = 0; -+ baud = i; -+ state = UBI32_UARTTIO_PARSE_STATE_TX_PIN; -+ break; -+ -+ case UBI32_UARTTIO_PARSE_STATE_TX_PIN: -+ tx_pin = i; -+ state = UBI32_UARTTIO_PARSE_STATE_RX_PIN; -+ break; -+ -+ case UBI32_UARTTIO_PARSE_STATE_RX_PIN: -+ rx_pin = i; -+ state = UBI32_UARTTIO_PARSE_STATE_HS; -+ break; -+ -+ case UBI32_UARTTIO_PARSE_STATE_HS: -+ hs = i; -+ if (hs) { -+ state = UBI32_UARTTIO_PARSE_STATE_CTS_PIN; -+ break; -+ } -+ -+ if (nfound == uarttio_inst.regs->max_uarts) { -+ printk(KERN_WARNING "Maximum number of serial ports reached\n"); -+ goto done; -+ } -+ nfound++; -+ state = UBI32_UARTTIO_PARSE_STATE_BAUD; -+ break; -+ -+ case UBI32_UARTTIO_PARSE_STATE_CTS_PIN: -+ cts_pin = i; -+ state = UBI32_UARTTIO_PARSE_STATE_RTS_PIN; -+ break; -+ -+ case UBI32_UARTTIO_PARSE_STATE_RTS_PIN: -+ rts_pin = i; -+ -+ if (nfound == uarttio_inst.regs->max_uarts) { -+ printk(KERN_WARNING "Maximum number of serial ports reached\n"); -+ goto done; -+ } -+ nfound++; -+ state = UBI32_UARTTIO_PARSE_STATE_BAUD; -+ break; -+ } -+ res = get_option(&str, &i); -+ } -+ -+ if ((res > 2) || state != UBI32_UARTTIO_PARSE_STATE_BAUD) { -+ printk(KERN_WARNING "Parameter syntax error.\n"); -+ res = -EINVAL; -+ goto fail; -+ } -+ -+ /* -+ * Create the final port -+ */ -+ if (ubi32_uarttio_setup_port(nfound - 1, uart, baud, tx_pin, rx_pin)) { -+ goto fail; -+ } -+ printk(KERN_INFO "Serial port %d: tx=%d:rx=%d @ %d\n", nfound, tx_pin, rx_pin, baud); -+ -+done: -+ uarttio_nports = nfound; -+ -+ return nfound ? 0 : -ENODEV; -+ -+fail: -+ /* -+ * Reset the ports -+ */ -+ uart = uarttio_inst.regs->uarts; -+ for (i = 0; i < uarttio_inst.regs->max_uarts; i++) { -+ uart->flags = 0; -+ uart++; -+ } -+ -+ return res; -+} -+ -+/* -+ * ubi32_uarttio_probe -+ */ -+static int ubi32_uarttio_probe(void) -+{ -+ int ret; -+ struct uarttio_node *uart_node; -+ char *str = utio_ports_param; -+ static int probed; -+ static int probe_result; -+ -+ /* -+ * We only want to be probed once, we could be probed twice -+ * for example if we are used as a console -+ */ -+ if (probed) { -+ return probe_result; -+ } -+ probed = 1; -+ -+ /* -+ * Extract the TIO name from the setup string -+ */ -+ while (*str) { -+ if (*str == ',') { -+ *str++ = 0; -+ break; -+ } -+ str++; -+ } -+ -+ if (!*str) { -+ probe_result = -EINVAL; -+ return -EINVAL; -+ } -+ -+ uart_node = (struct uarttio_node *)devtree_find_node(utio_ports_param); -+ if (!uart_node) { -+ probe_result = -ENODEV; -+ return -ENODEV; -+ } -+ -+ uarttio_inst.irq = uart_node->dn.recvirq; -+ uarttio_inst.regs = uart_node->regs; -+ -+ /* -+ * Parse module parameters. -+ */ -+ ret = ubi32_uarttio_parse_param(str); -+ if (ret != 0) { -+ ubi32_uarttio_cleanup(); -+ probe_result = ret; -+ return ret; -+ } -+ -+ ubi32_uarttio_uart_driver.nr = uarttio_nports; -+ -+ return 0; -+} -+ -+#if defined(CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE) -+/* -+ * ubi32_uarttio_console_setup -+ */ -+static int __init ubi32_uarttio_console_setup(struct console *co, char *options) -+{ -+ int baud; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+ struct ubi32_uarttio_port *uup; -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ if (co->index == -1 || co->index >= uarttio_nports) { -+ co->index = 0; -+ } -+ uup = &uarttio_ports[co->index]; -+ baud = uup->uart->baud_rate; -+ uup->uart->flags |= UARTTIO_UART_FLAG_ENABLED; -+ -+ /* -+ * Setup the GPIOs -+ * We have to use the direct interface because the gpio -+ * subsystem is not available at this point. -+ */ -+ uup->port_init = 1; -+ UBICOM32_GPIO_SET_PIN_HIGH(uup->tx_pin); -+ UBICOM32_GPIO_SET_PIN_OUTPUT(uup->tx_pin); -+ UBICOM32_GPIO_SET_PIN_INPUT(uup->rx_pin); -+ -+ /* -+ * Start the thread -+ */ -+ thread_enable(uarttio_inst.regs->thread); -+ -+ /* -+ * Process options -+ */ -+ if (options) { -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ if (ubi32_uarttio_set_baud(uup, baud)) { -+ baud = uup->uart->current_baud_rate; -+ } -+ } -+ -+ return uart_set_options(&uup->port, co, baud, 'n', 8, 'n'); -+} -+ -+/* -+ * ubi32_uarttio_console_putchar -+ */ -+static void ubi32_uarttio_console_putchar(struct uart_port *port, int ch) -+{ -+ struct ubi32_uarttio_port *uup = port->private_data; -+ -+ while (ubi32_uarttio_put_char(uup->uart, ch)) { -+ cpu_relax(); -+ } -+} -+ -+/* -+ * ubi32_uarttio_console_write -+ * Interrupts are disabled on entering -+ */ -+static void ubi32_uarttio_console_write(struct console *co, const char *s, unsigned int count) -+{ -+ struct uart_port *port = &(uarttio_ports[co->index].port); -+ unsigned long flags = 0; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ uart_console_write(port, s, count, ubi32_uarttio_console_putchar); -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static struct console ubi32_uarttio_console = { -+ .name = UBI32_UARTTIO_NAME, -+ .write = ubi32_uarttio_console_write, -+ .device = uart_console_device, -+ .setup = ubi32_uarttio_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+ .data = &ubi32_uarttio_uart_driver, -+}; -+ -+static int __init ubi32_uarttio_console_init(void) -+{ -+ int res; -+ -+ res = ubi32_uarttio_probe(); -+ if (res) { -+ return res; -+ } -+ -+ register_console(&ubi32_uarttio_console); -+ return 0; -+} -+console_initcall(ubi32_uarttio_console_init); -+#endif /* CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE */ -+ -+/* -+ * ubi32_serial_suspend -+ */ -+static int ubi32_uarttio_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ int i; -+ for (i = 0; i < uarttio_nports; i++) { -+ uart_suspend_port(&ubi32_uarttio_uart_driver, &uarttio_ports[i].port); -+ } -+ -+ return 0; -+} -+ -+/* -+ * ubi32_serial_resume -+ */ -+static int ubi32_uarttio_resume(struct platform_device *pdev) -+{ -+ int i; -+ for (i = 0; i < uarttio_nports; i++) { -+ uart_resume_port(&ubi32_uarttio_uart_driver, &uarttio_ports[i].port); -+ } -+ -+ return 0; -+} -+ -+/* -+ * ubi32_uarttio_remove -+ */ -+static int __devexit ubi32_uarttio_remove(struct platform_device *pdev) -+{ -+ ubi32_uarttio_cleanup(); -+ -+ uart_unregister_driver(&ubi32_uarttio_uart_driver); -+ -+ return 0; -+} -+ -+static struct platform_driver ubi32_uarttio_platform_driver = { -+ .remove = __devexit_p(ubi32_uarttio_remove), -+ .suspend = ubi32_uarttio_suspend, -+ .resume = ubi32_uarttio_resume, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+#ifndef MODULE -+/* -+ * Called at boot time. -+ * -+ * uarttio=TIONAME,(baud,tx_pin,rx_pin,handshake[,cts_pin,rts_pin],...) -+ * TIONAME is the name of the devtree node which describes the UARTTIO -+ * pin is the index of the pin, i.e. PA4 is 5 [(port * 32) + pin] -+ * handshake = 1 to enable handshaking, provide cts_pin, rts_pin (UNSUPPORTED) -+ * handshake = 0 to disable handshaking, do not provide cts_pin, rts_pin -+ * Ex: uarttio=UARTTIO,57600,7,6,0,9600,8,9,0 -+ */ -+static int __init ubi32_uarttio_setup(char *str) -+{ -+ strncpy(utio_ports_param, str, UBI32_UARTTIO_MAX_PARAM_LEN); -+ utio_ports_param[UBI32_UARTTIO_MAX_PARAM_LEN - 1] = 0; -+ return 1; -+} -+__setup("uarttio=", ubi32_uarttio_setup); -+#endif -+ -+/* -+ * ubi32_uarttio_init -+ */ -+static int __init ubi32_uarttio_init(void) -+{ -+ int ret; -+ int i; -+ -+ ret = ubi32_uarttio_probe(); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * Request the IRQ (do it here since many ports share the same IRQ) -+ */ -+ ret = request_irq(uarttio_inst.irq, ubi32_uarttio_isr, IRQF_DISABLED, DRIVER_NAME, NULL); -+ if (ret != 0) { -+ printk(KERN_WARNING "Could not request IRQ %d\n", uarttio_inst.irq); -+ goto fail; -+ } -+ uarttio_inst.irq_requested = 1; -+ -+ /* -+ * Register the UART driver and add the ports -+ */ -+ ret = uart_register_driver(&ubi32_uarttio_uart_driver); -+ if (ret != 0) { -+ goto fail; -+ } -+ uarttio_inst.driver_registered = 1; -+ -+ ret = ubi32_uarttio_add_ports(); -+ if (ret != 0) { -+ ubi32_uarttio_cleanup(); -+ return ret; -+ } -+ -+ /* -+ * Start the thread -+ */ -+ thread_enable(uarttio_inst.regs->thread); -+ -+ for (i = 0; i < uarttio_nports; i++) { -+ pr_info("Serial: Ubicom32 uarttio #%d: tx:%d rx:%d baud:%d\n", -+ i, uarttio_ports[i].tx_pin, uarttio_ports[i].rx_pin, -+ uarttio_ports[i].uart->current_baud_rate); -+ } -+ pr_info("Serial: Ubicom32 uarttio started on thread:%d irq:%d\n", uarttio_inst.regs->thread, uarttio_inst.irq); -+ -+ return ret; -+ -+fail: -+ ubi32_uarttio_cleanup(); -+ return ret; -+} -+module_init(ubi32_uarttio_init); -+ -+/* -+ * ubi32_uarttio_exit -+ */ -+static void __exit ubi32_uarttio_exit(void) -+{ -+ platform_driver_unregister(&ubi32_uarttio_platform_driver); -+} -+module_exit(ubi32_uarttio_exit); -+ -+module_param_string(ports, utio_ports_param, sizeof(utio_ports_param), 0444); -+MODULE_PARM_DESC(ports, "Sets the ports to allocate: ports=TIONAME,(baud,txpin,rxpin,handshake[,ctspin,rtspin],...)\n" -+ " TIONAME is the name of the devtree node which describes the UARTTIO\n" -+ " pin is the index of the pin, i.e. PA4 is 5 [(port * 32) + pin]\n" -+ " handshake = 1 to enable handshaking, provide ctspin, rtspin (UNSUPPORTED)\n" -+ " handshake = 0 to disable handshaking, do not provide ctspin, rtspin\n" -+ " Ex: ports=UARTTIO,57600,7,6,0,9600,8,9,0\n"); -+MODULE_AUTHOR("Patrick Tjin "); -+MODULE_DESCRIPTION("Ubicom serial virtual peripherial driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS_CHARDEV_MAJOR(UBI32_UARTTIO_MAJOR); -+MODULE_ALIAS("platform:" DRIVER_NAME); -diff -ruN linux-2.6.30.10/drivers/spi/Kconfig linux-2.6.30.10-ubi/drivers/spi/Kconfig ---- linux-2.6.30.10/drivers/spi/Kconfig 2009-12-14 11:54:29.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/spi/Kconfig 2009-12-14 11:54:27.000000000 +0200 -@@ -196,6 +196,15 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -196,6 +196,15 @@ config SPI_S3C24XX help SPI driver for Samsung S3C24XX series ARM SoCs @@ -50022,10 +353,9 @@ diff -ruN linux-2.6.30.10/drivers/spi/Kconfig linux-2.6.30.10-ubi/drivers/spi/Kc config SPI_S3C24XX_GPIO tristate "Samsung S3C24XX series SPI by GPIO" depends on ARCH_S3C2410 && EXPERIMENTAL -diff -ruN linux-2.6.30.10/drivers/spi/Makefile linux-2.6.30.10-ubi/drivers/spi/Makefile ---- linux-2.6.30.10/drivers/spi/Makefile 2009-12-14 11:55:29.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/spi/Makefile 2009-12-14 11:55:25.000000000 +0200 -@@ -27,6 +27,7 @@ +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_ORION) += orion_spi.o obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o @@ -50033,281 +363,9 @@ diff -ruN linux-2.6.30.10/drivers/spi/Makefile linux-2.6.30.10-ubi/drivers/spi/M obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o obj-$(CONFIG_SPI_TXX9) += spi_txx9.o obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o -diff -ruN linux-2.6.30.10/drivers/spi/spi_ubicom32_gpio.c linux-2.6.30.10-ubi/drivers/spi/spi_ubicom32_gpio.c ---- linux-2.6.30.10/drivers/spi/spi_ubicom32_gpio.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/spi/spi_ubicom32_gpio.c 2009-12-11 11:45:19.000000000 +0200 -@@ -0,0 +1,267 @@ -+/* -+ * drivers/spi_spi_ubicom32_gpio.c -+ * Ubicom32 GPIO based SPI driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+#include -+ -+#define DRIVER_NAME "ubicom32-spi-gpio" -+ -+struct ubicom32_spi_gpio { -+ struct spi_bitbang bitbang; -+ -+ struct ubicom32_spi_gpio_platform_data *pdata; -+ -+ struct platform_device *dev; -+}; -+ -+/* -+ * The following 4 functions are used by EXPAND_BITBANG_TXRX to bitbang the data out. -+ */ -+static inline void setsck(struct spi_device *dev, int on) -+{ -+ struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master); -+ gpio_set_value(usg->pdata->pin_clk, on ? 1 : 0); -+} -+ -+static inline void setmosi(struct spi_device *dev, int on) -+{ -+ struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master); -+ gpio_set_value(usg->pdata->pin_mosi, on ? 1 : 0); -+} -+ -+static inline u32 getmiso(struct spi_device *dev) -+{ -+ struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master); -+ return gpio_get_value(usg->pdata->pin_miso) ? 1 : 0; -+} -+ -+#define spidelay(x) ndelay(x) -+ -+#define EXPAND_BITBANG_TXRX -+#include -+ -+/* -+ * ubicom32_spi_gpio_txrx_mode0 -+ */ -+static u32 ubicom32_spi_gpio_txrx_mode0(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) -+{ -+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); -+} -+ -+/* -+ * ubicom32_spi_gpio_txrx_mode1 -+ */ -+static u32 ubicom32_spi_gpio_txrx_mode1(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) -+{ -+ return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits); -+} -+ -+/* -+ * ubicom32_spi_gpio_txrx_mode2 -+ */ -+static u32 ubicom32_spi_gpio_txrx_mode2(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) -+{ -+ return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits); -+} -+ -+/* -+ * ubicom32_spi_gpio_txrx_mode3 -+ */ -+static u32 ubicom32_spi_gpio_txrx_mode3(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) -+{ -+ return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits); -+} -+ -+/* -+ * ubicom32_spi_gpio_chipselect -+ */ -+static void ubicom32_spi_gpio_chipselect(struct spi_device *dev, int value) -+{ -+ struct ubicom32_spi_gpio_controller_data *cd = (struct ubicom32_spi_gpio_controller_data *)dev->controller_data; -+ unsigned int cs_polarity = dev->mode & SPI_CS_HIGH ? 1 : 0; -+ -+ if (value == BITBANG_CS_ACTIVE) { -+ gpio_set_value(cd->pin_cs, cs_polarity); -+ return; -+ } -+ gpio_set_value(cd->pin_cs, !cs_polarity); -+} -+ -+/* -+ * ubicom32_spi_gpio_probe -+ */ -+static int ubicom32_spi_gpio_probe(struct platform_device *dev) -+{ -+ struct ubicom32_spi_gpio_platform_data *pdata; -+ struct spi_master *master; -+ struct ubicom32_spi_gpio *usg; -+ int ret; -+ -+ master = spi_alloc_master(&dev->dev, sizeof(struct ubicom32_spi_gpio)); -+ if (master == NULL) { -+ dev_err(&dev->dev, "failed to allocate spi master\n"); -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(master); -+ -+ platform_set_drvdata(dev, usg); -+ -+ /* -+ * Copy in the platform data -+ */ -+ pdata = dev->dev.platform_data; -+ usg->pdata = dev->dev.platform_data; -+ -+ /* -+ * Request the GPIO lines -+ */ -+ ret = gpio_request(pdata->pin_mosi, "spi-mosi"); -+ if (ret) { -+ dev_err(&dev->dev, "Failed to allocate spi-mosi GPIO\n"); -+ goto err; -+ } -+ -+ ret = gpio_request(pdata->pin_miso, "spi-miso"); -+ if (ret) { -+ dev_err(&dev->dev, "Failed to allocate spi-miso GPIO\n"); -+ goto err_nomiso; -+ } -+ -+ ret = gpio_request(pdata->pin_clk, "spi-clk"); -+ if (ret) { -+ dev_err(&dev->dev, "Failed to allocate spi-clk GPIO\n"); -+ goto err_noclk; -+ } -+ -+ /* -+ * Setup spi-bitbang adaptor -+ */ -+ usg->bitbang.flags |= SPI_CS_HIGH; -+ usg->bitbang.master = spi_master_get(master); -+ usg->bitbang.master->bus_num = pdata->bus_num; -+ usg->bitbang.master->num_chipselect = pdata->num_chipselect; -+ usg->bitbang.chipselect = ubicom32_spi_gpio_chipselect; -+ -+ usg->bitbang.txrx_word[SPI_MODE_0] = ubicom32_spi_gpio_txrx_mode0; -+ usg->bitbang.txrx_word[SPI_MODE_1] = ubicom32_spi_gpio_txrx_mode1; -+ usg->bitbang.txrx_word[SPI_MODE_2] = ubicom32_spi_gpio_txrx_mode2; -+ usg->bitbang.txrx_word[SPI_MODE_3] = ubicom32_spi_gpio_txrx_mode3; -+ -+ /* -+ * Setup the GPIO pins -+ */ -+ gpio_direction_output(pdata->pin_clk, pdata->clk_default); -+ gpio_direction_output(pdata->pin_mosi, 0); -+ gpio_direction_input(pdata->pin_miso); -+ -+ /* -+ * Ready to go -+ */ -+ ret = spi_bitbang_start(&usg->bitbang); -+ if (ret) { -+ goto err_no_bitbang; -+ } -+ -+ return 0; -+ -+err_no_bitbang: -+ spi_master_put(usg->bitbang.master); -+ -+ gpio_free(pdata->pin_clk); -+ -+err_noclk: -+ gpio_free(pdata->pin_miso); -+ -+err_nomiso: -+ gpio_free(pdata->pin_mosi); -+ -+err: -+ return ret; -+} -+ -+/* -+ * ubicom32_spi_gpio_remove -+ */ -+static int ubicom32_spi_gpio_remove(struct platform_device *dev) -+{ -+ struct ubicom32_spi_gpio *sp = platform_get_drvdata(dev); -+ -+ spi_bitbang_stop(&sp->bitbang); -+ spi_master_put(sp->bitbang.master); -+ -+ return 0; -+} -+ -+/* -+ * Work with hotplug and coldplug -+ */ -+MODULE_ALIAS("platform:ubicom32_spi_gpio"); -+ -+static struct platform_driver ubicom32_spi_gpio_drv = { -+ .probe = ubicom32_spi_gpio_probe, -+ .remove = ubicom32_spi_gpio_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+/* -+ * ubicom32_spi_gpio_init -+ */ -+static int __init ubicom32_spi_gpio_init(void) -+{ -+ return platform_driver_register(&ubicom32_spi_gpio_drv); -+} -+ -+/* -+ * ubicom32_spi_gpio_exit -+ */ -+static void __exit ubicom32_spi_gpio_exit(void) -+{ -+ platform_driver_unregister(&ubicom32_spi_gpio_drv); -+} -+ -+module_init(ubicom32_spi_gpio_init); -+module_exit(ubicom32_spi_gpio_exit); -+ -+MODULE_DESCRIPTION("Ubicom32 SPI-GPIO Driver"); -+MODULE_AUTHOR("Pat Tjin, <@ubicom.com>"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/drivers/uio/Kconfig linux-2.6.30.10-ubi/drivers/uio/Kconfig ---- linux-2.6.30.10/drivers/uio/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/uio/Kconfig 2009-12-11 11:45:20.000000000 +0200 -@@ -89,4 +89,12 @@ +--- a/drivers/uio/Kconfig ++++ b/drivers/uio/Kconfig +@@ -89,4 +89,12 @@ config UIO_SERCOS3 If you compile this as a module, it will be called uio_sercos3. @@ -50320,310 +378,16 @@ diff -ruN linux-2.6.30.10/drivers/uio/Kconfig linux-2.6.30.10-ubi/drivers/uio/Kc + If you compile this as a module, it will be called uio_ubicom32ring + endif -diff -ruN linux-2.6.30.10/drivers/uio/Makefile linux-2.6.30.10-ubi/drivers/uio/Makefile ---- linux-2.6.30.10/drivers/uio/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/uio/Makefile 2009-12-11 11:45:20.000000000 +0200 -@@ -5,3 +5,4 @@ +--- a/drivers/uio/Makefile ++++ b/drivers/uio/Makefile +@@ -5,3 +5,4 @@ obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdr obj-$(CONFIG_UIO_SMX) += uio_smx.o obj-$(CONFIG_UIO_AEC) += uio_aec.o obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o +obj-$(CONFIG_UIO_UBICOM32RING) += uio_ubicom32ring.o -diff -ruN linux-2.6.30.10/drivers/uio/uio_ubicom32ring.c linux-2.6.30.10-ubi/drivers/uio/uio_ubicom32ring.c ---- linux-2.6.30.10/drivers/uio/uio_ubicom32ring.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/uio/uio_ubicom32ring.c 2009-12-11 11:45:20.000000000 +0200 -@@ -0,0 +1,288 @@ -+/* -+ * drivers/uio/uio_ubicom32ring.c -+ * -+ * Userspace I/O platform driver for Ubicom32 ring buffers -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * Based on uio_ubicom32ring.c by Magnus Damm -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define DRIVER_NAME "uio_ubicom32ring" -+ -+struct uio_ubicom32ring_data { -+ struct uio_info *uioinfo; -+ -+ struct uio_ubicom32ring_regs *regs; -+ -+ /* -+ * IRQ used to kick the ring buffer -+ */ -+ int irq_tx; -+ int irq_rx; -+ -+ spinlock_t lock; -+ -+ unsigned long flags; -+ -+ char name[0]; -+}; -+ -+static irqreturn_t uio_ubicom32ring_handler(int irq, struct uio_info *dev_info) -+{ -+ struct uio_ubicom32ring_data *priv = dev_info->priv; -+ -+ /* Just disable the interrupt in the interrupt controller, and -+ * remember the state so we can allow user space to enable it later. -+ */ -+ -+ if (!test_and_set_bit(0, &priv->flags)) -+ disable_irq_nosync(irq); -+ -+ return IRQ_HANDLED; -+} -+ -+static int uio_ubicom32ring_irqcontrol(struct uio_info *dev_info, s32 irq_on) -+{ -+ struct uio_ubicom32ring_data *priv = dev_info->priv; -+ unsigned long flags; -+ -+ /* Allow user space to enable and disable the interrupt -+ * in the interrupt controller, but keep track of the -+ * state to prevent per-irq depth damage. -+ * -+ * Serialize this operation to support multiple tasks. -+ */ -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ -+ if (irq_on & 2) { -+ /* -+ * Kick the ring buffer (if we can) -+ */ -+ if (priv->irq_tx != 0xFF) { -+ ubicom32_set_interrupt(priv->irq_tx); -+ } -+ } -+ -+ if (priv->irq_rx != 0xFF) { -+ if (irq_on & 1) { -+ if (test_and_clear_bit(0, &priv->flags)) -+ enable_irq(dev_info->irq); -+ } else { -+ if (!test_and_set_bit(0, &priv->flags)) -+ disable_irq(dev_info->irq); -+ } -+ } -+ -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ return 0; -+} -+ -+static int uio_ubicom32ring_probe(struct platform_device *pdev) -+{ -+ struct uio_info *uioinfo; -+ struct uio_mem *uiomem; -+ struct uio_ubicom32ring_data *priv; -+ struct uio_ubicom32ring_regs *regs; -+ struct resource *mem_resource; -+ struct resource *irqtx_resource; -+ struct resource *irqrx_resource; -+ int ret = -EINVAL; -+ int i; -+ -+ uioinfo = kzalloc(sizeof(struct uio_info), GFP_KERNEL); -+ if (!uioinfo) { -+ dev_err(&pdev->dev, "unable to kmalloc\n"); -+ return -ENOMEM; -+ } -+ -+ /* -+ * Allocate private data with some string space after -+ */ -+ i = sizeof(DRIVER_NAME) + 1; -+ i += pdev->dev.platform_data ? strlen(pdev->dev.platform_data) : 0; -+ priv = kzalloc(sizeof(struct uio_ubicom32ring_data) + i, GFP_KERNEL); -+ if (!priv) { -+ dev_err(&pdev->dev, "unable to kmalloc\n"); -+ kfree(uioinfo); -+ return -ENOMEM; -+ } -+ -+ strcpy(priv->name, DRIVER_NAME ":"); -+ if (pdev->dev.platform_data) { -+ strcat(priv->name, pdev->dev.platform_data); -+ } -+ uioinfo->priv = priv; -+ uioinfo->name = priv->name; -+ uioinfo->version = "0.1"; -+ -+ priv->uioinfo = uioinfo; -+ spin_lock_init(&priv->lock); -+ priv->flags = 0; /* interrupt is enabled to begin with */ -+ -+ /* -+ * Get our resources, the IRQ_TX and IRQ_RX are optional. -+ */ -+ priv->irq_tx = 0xFF; -+ irqtx_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -+ if (irqtx_resource) { -+ priv->irq_tx = irqtx_resource->start; -+ } -+ -+ uioinfo->irq = -1; -+ priv->irq_rx = 0xFF; -+ irqrx_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 1); -+ if (irqrx_resource) { -+ priv->irq_rx = irqrx_resource->start; -+ uioinfo->irq = priv->irq_rx; -+ uioinfo->handler = uio_ubicom32ring_handler; -+ } -+ -+ mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!mem_resource || !mem_resource->start) { -+ dev_err(&pdev->dev, "No valid memory resource found\n"); -+ ret = -ENODEV; -+ goto fail; -+ } -+ regs = (struct uio_ubicom32ring_regs *)mem_resource->start; -+ priv->regs = regs; -+ -+ if (regs->version != UIO_UBICOM32RING_REG_VERSION) { -+ dev_err(&pdev->dev, "version %d not supported\n", regs->version); -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ /* -+ * First range is the shared register space, if we have any -+ */ -+ uiomem = &uioinfo->mem[0]; -+ if (regs->regs_size) { -+ uiomem->memtype = UIO_MEM_PHYS; -+ uiomem->addr = (u32_t)regs->regs; -+ uiomem->size = regs->regs_size; -+ ++uiomem; -+ dev_info(&pdev->dev, "regs:%p (%u) / rings: %d found\n", regs->regs, regs->regs_size, regs->num_rings); -+ } else { -+ dev_info(&pdev->dev, "rings: %d found\n", regs->num_rings); -+ } -+ -+ /* -+ * The rest of the range correspond to the rings -+ */ -+ for (i = 0; i < regs->num_rings; i++) { -+ dev_info(&pdev->dev, "\t%d: entries:%d ring:%p\n", -+ i, regs->rings[i]->entries, &(regs->rings[i]->ring)); -+ if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { -+ dev_warn(&pdev->dev, "device has more than " -+ __stringify(MAX_UIO_MAPS) -+ " I/O memory resources.\n"); -+ break; -+ } -+ -+ uiomem->memtype = UIO_MEM_PHYS; -+ uiomem->addr = (u32_t)&(regs->rings[i]->head); -+ uiomem->size = (regs->rings[i]->entries * sizeof(u32_t)) + -+ sizeof(struct uio_ubicom32ring_desc); -+ ++uiomem; -+ } -+ -+ while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) { -+ uiomem->size = 0; -+ ++uiomem; -+ } -+ -+ /* This driver requires no hardware specific kernel code to handle -+ * interrupts. Instead, the interrupt handler simply disables the -+ * interrupt in the interrupt controller. User space is responsible -+ * for performing hardware specific acknowledge and re-enabling of -+ * the interrupt in the interrupt controller. -+ * -+ * Interrupt sharing is not supported. -+ */ -+ uioinfo->irq_flags = IRQF_DISABLED; -+ uioinfo->irqcontrol = uio_ubicom32ring_irqcontrol; -+ -+ ret = uio_register_device(&pdev->dev, priv->uioinfo); -+ if (ret) { -+ dev_err(&pdev->dev, "unable to register uio device\n"); -+ goto fail; -+ } -+ -+ platform_set_drvdata(pdev, priv); -+ -+ dev_info(&pdev->dev, "'%s' using irq: rx %d tx %d, regs %p\n", -+ priv->name, priv->irq_rx, priv->irq_tx, priv->regs); -+ -+ return 0; -+ -+fail: -+ kfree(uioinfo); -+ kfree(priv); -+ return ret; -+} -+ -+static int uio_ubicom32ring_remove(struct platform_device *pdev) -+{ -+ struct uio_ubicom32ring_data *priv = platform_get_drvdata(pdev); -+ -+ uio_unregister_device(priv->uioinfo); -+ kfree(priv->uioinfo); -+ kfree(priv); -+ return 0; -+} -+ -+static struct platform_driver uio_ubicom32ring = { -+ .probe = uio_ubicom32ring_probe, -+ .remove = uio_ubicom32ring_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init uio_ubicom32ring_init(void) -+{ -+ return platform_driver_register(&uio_ubicom32ring); -+} -+ -+static void __exit uio_ubicom32ring_exit(void) -+{ -+ platform_driver_unregister(&uio_ubicom32ring); -+} -+ -+module_init(uio_ubicom32ring_init); -+module_exit(uio_ubicom32ring_exit); -+ -+MODULE_AUTHOR("Patrick Tjin"); -+MODULE_DESCRIPTION("Userspace I/O driver for Ubicom32 ring buffers"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:" DRIVER_NAME); -diff -ruN linux-2.6.30.10/drivers/usb/gadget/epautoconf.c linux-2.6.30.10-ubi/drivers/usb/gadget/epautoconf.c ---- linux-2.6.30.10/drivers/usb/gadget/epautoconf.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/gadget/epautoconf.c 2009-12-11 11:45:20.000000000 +0200 -@@ -154,6 +154,10 @@ +--- a/drivers/usb/gadget/epautoconf.c ++++ b/drivers/usb/gadget/epautoconf.c +@@ -154,6 +154,10 @@ ep_matches ( /* configure your hardware with enough buffering!! */ } break; @@ -50634,10 +398,9 @@ diff -ruN linux-2.6.30.10/drivers/usb/gadget/epautoconf.c linux-2.6.30.10-ubi/dr } /* MATCH!! */ -diff -ruN linux-2.6.30.10/drivers/usb/Kconfig linux-2.6.30.10-ubi/drivers/usb/Kconfig ---- linux-2.6.30.10/drivers/usb/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/Kconfig 2009-12-11 11:45:20.000000000 +0200 -@@ -22,6 +22,7 @@ +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -22,6 +22,7 @@ config USB_ARCH_HAS_HCD default y if PCMCIA && !M32R # sl811_cs default y if ARM # SL-811 default y if SUPERH # r8a66597-hcd @@ -50645,10 +408,9 @@ diff -ruN linux-2.6.30.10/drivers/usb/Kconfig linux-2.6.30.10-ubi/drivers/usb/Kc default PCI # many non-PCI SOC chips embed OHCI -diff -ruN linux-2.6.30.10/drivers/usb/musb/Kconfig linux-2.6.30.10-ubi/drivers/usb/musb/Kconfig ---- linux-2.6.30.10/drivers/usb/musb/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/Kconfig 2009-12-11 11:45:20.000000000 +0200 -@@ -12,7 +12,7 @@ +--- a/drivers/usb/musb/Kconfig ++++ b/drivers/usb/musb/Kconfig +@@ -12,7 +12,7 @@ config USB_MUSB_HDRC depends on !SUPERH select TWL4030_USB if MACH_OMAP_3430SDP select USB_OTG_UTILS @@ -50657,10 +419,9 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/Kconfig linux-2.6.30.10-ubi/drivers/u help Say Y here if your system has a dual role high speed USB controller based on the Mentor Graphics silicon IP. Then -diff -ruN linux-2.6.30.10/drivers/usb/musb/Makefile linux-2.6.30.10-ubi/drivers/usb/musb/Makefile ---- linux-2.6.30.10/drivers/usb/musb/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/Makefile 2009-12-11 11:45:20.000000000 +0200 -@@ -30,6 +30,10 @@ +--- a/drivers/usb/musb/Makefile ++++ b/drivers/usb/musb/Makefile +@@ -30,6 +30,10 @@ ifeq ($(CONFIG_BF52x),y) musb_hdrc-objs += blackfin.o endif @@ -50671,9 +432,8 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/Makefile linux-2.6.30.10-ubi/drivers/ ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y) musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o endif -diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drivers/usb/musb/musb_core.c ---- linux-2.6.30.10/drivers/usb/musb/musb_core.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/musb_core.c 2009-12-11 11:45:20.000000000 +0200 +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c @@ -105,6 +105,13 @@ #include #endif @@ -50688,7 +448,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive #include "musb_core.h" -@@ -147,8 +154,37 @@ +@@ -147,8 +154,37 @@ static inline struct musb *dev_to_musb(s } /*-------------------------------------------------------------------------*/ @@ -50727,7 +487,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive /* * Load an endpoint's FIFO -@@ -227,8 +263,7 @@ +@@ -227,8 +263,7 @@ void musb_read_fifo(struct musb_hw_ep *h readsb(fifo, dst, len); } } @@ -50737,7 +497,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive /*-------------------------------------------------------------------------*/ -@@ -874,12 +909,19 @@ +@@ -874,12 +909,19 @@ void musb_start(struct musb *musb) musb_writeb(regs, MUSB_TESTMODE, 0); /* put into basic highspeed mode and start session */ @@ -50757,7 +517,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive musb->is_active = 0; devctl = musb_readb(regs, MUSB_DEVCTL); -@@ -1081,6 +1123,7 @@ +@@ -1081,6 +1123,7 @@ static struct fifo_cfg __initdata mode_4 }; @@ -50765,7 +525,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive /* * configure a fifo; for non-shared endpoints, this may be called * once for a tx fifo and once for an rx fifo. -@@ -1240,7 +1283,7 @@ +@@ -1240,7 +1283,7 @@ static int __init ep_config_from_table(s return 0; } @@ -50774,7 +534,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive /* * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false -@@ -1256,6 +1299,11 @@ +@@ -1256,6 +1299,11 @@ static int __init ep_config_from_hw(stru DBG(2, "<== static silicon ep config\n"); /* FIXME pick up ep0 maxpacket size */ @@ -50786,7 +546,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive for (epnum = 1; epnum < musb->config->num_eps; epnum++) { musb_ep_select(mbase, epnum); -@@ -1276,14 +1324,27 @@ +@@ -1276,14 +1324,27 @@ static int __init ep_config_from_hw(stru /* REVISIT: this algorithm is lazy, we should at least * try to pick a double buffered endpoint. */ @@ -50815,7 +575,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive pr_debug("%s: missing bulk\n", musb_driver_name); return -EINVAL; } -@@ -1393,12 +1454,16 @@ +@@ -1393,12 +1454,16 @@ static int __init musb_core_init(u16 mus musb->epmask = 1; if (reg & MUSB_CONFIGDATA_DYNFIFO) { @@ -50833,7 +593,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive } else { if (!musb->config->dyn_fifo) status = ep_config_from_hw(musb); -@@ -1462,8 +1527,8 @@ +@@ -1462,8 +1527,8 @@ static int __init musb_core_init(u16 mus /*-------------------------------------------------------------------------*/ @@ -50844,7 +604,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive static irqreturn_t generic_interrupt(int irq, void *__hci) { unsigned long flags; -@@ -1472,10 +1537,17 @@ +@@ -1472,10 +1537,17 @@ static irqreturn_t generic_interrupt(int spin_lock_irqsave(&musb->lock, flags); @@ -50862,7 +622,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive if (musb->int_usb || musb->int_tx || musb->int_rx) retval = musb_interrupt(musb); -@@ -2210,6 +2282,10 @@ +@@ -2210,6 +2282,10 @@ static struct platform_driver musb_drive static int __init musb_init(void) { @@ -50873,10 +633,9 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.c linux-2.6.30.10-ubi/drive #ifdef CONFIG_USB_MUSB_HDRC_HCD if (usb_disabled()) return 0; -diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.h linux-2.6.30.10-ubi/drivers/usb/musb/musb_core.h ---- linux-2.6.30.10/drivers/usb/musb/musb_core.h 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/musb_core.h 2009-12-11 11:45:20.000000000 +0200 -@@ -326,7 +326,12 @@ +--- a/drivers/usb/musb/musb_core.h ++++ b/drivers/usb/musb/musb_core.h +@@ -326,7 +326,12 @@ struct musb { * queue until it completes or NAKs too much; then we try the next * endpoint. */ @@ -50889,10 +648,9 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_core.h linux-2.6.30.10-ubi/drive struct list_head control; /* of musb_qh */ struct list_head in_bulk; /* of musb_qh */ -diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget.c linux-2.6.30.10-ubi/drivers/usb/musb/musb_gadget.c ---- linux-2.6.30.10/drivers/usb/musb/musb_gadget.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/musb_gadget.c 2009-12-11 11:45:20.000000000 +0200 -@@ -432,7 +432,7 @@ +--- a/drivers/usb/musb/musb_gadget.c ++++ b/drivers/usb/musb/musb_gadget.c +@@ -432,7 +432,7 @@ void musb_g_tx(struct musb *musb, u8 epn * probably rates reporting as a host error */ if (csr & MUSB_TXCSR_P_SENTSTALL) { @@ -50901,7 +659,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget.c linux-2.6.30.10-ubi/dri csr &= ~MUSB_TXCSR_P_SENTSTALL; musb_writew(epio, MUSB_TXCSR, csr); if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { -@@ -448,7 +448,7 @@ +@@ -448,7 +448,7 @@ void musb_g_tx(struct musb *musb, u8 epn if (csr & MUSB_TXCSR_P_UNDERRUN) { /* we NAKed, no big deal ... little reason to care */ @@ -50910,7 +668,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget.c linux-2.6.30.10-ubi/dri csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); musb_writew(epio, MUSB_TXCSR, csr); -@@ -584,10 +584,16 @@ +@@ -584,10 +584,16 @@ static void rxstate(struct musb *musb, s u16 csr = 0; const u8 epnum = req->epnum; struct usb_request *request = &req->request; @@ -50930,7 +688,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget.c linux-2.6.30.10-ubi/dri csr = musb_readw(epio, MUSB_RXCSR); -@@ -726,7 +732,7 @@ +@@ -726,7 +732,7 @@ static void rxstate(struct musb *musb, s */ /* ack the read! */ @@ -50939,7 +697,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget.c linux-2.6.30.10-ubi/dri csr &= ~MUSB_RXCSR_RXPKTRDY; musb_writew(epio, MUSB_RXCSR, csr); } -@@ -745,10 +751,15 @@ +@@ -745,10 +751,15 @@ void musb_g_rx(struct musb *musb, u8 epn u16 csr; struct usb_request *request; void __iomem *mbase = musb->mregs; @@ -50956,7 +714,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget.c linux-2.6.30.10-ubi/dri musb_ep_select(mbase, epnum); request = next_request(musb_ep); -@@ -1769,7 +1780,9 @@ +@@ -1769,7 +1780,9 @@ int usb_gadget_register_driver(struct us } } } @@ -50967,10 +725,9 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget.c linux-2.6.30.10-ubi/dri return retval; } EXPORT_SYMBOL(usb_gadget_register_driver); -diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget_ep0.c linux-2.6.30.10-ubi/drivers/usb/musb/musb_gadget_ep0.c ---- linux-2.6.30.10/drivers/usb/musb/musb_gadget_ep0.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/musb_gadget_ep0.c 2009-12-11 11:45:20.000000000 +0200 -@@ -240,14 +240,14 @@ +--- a/drivers/usb/musb/musb_gadget_ep0.c ++++ b/drivers/usb/musb/musb_gadget_ep0.c +@@ -240,14 +240,14 @@ __acquires(musb->lock) case USB_REQ_SET_ADDRESS: /* change it after the status stage */ musb->set_address = true; @@ -50987,7 +744,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget_ep0.c linux-2.6.30.10-ubi != USB_DEVICE_REMOTE_WAKEUP) break; musb->may_wakeup = 0; -@@ -261,8 +261,8 @@ +@@ -261,8 +261,8 @@ __acquires(musb->lock) if (num == 0 || num >= MUSB_C_NUM_EPS @@ -50998,7 +755,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget_ep0.c linux-2.6.30.10-ubi break; if (ctrlrequest->wIndex & USB_DIR_IN) -@@ -292,7 +292,7 @@ +@@ -292,7 +292,7 @@ __acquires(musb->lock) switch (recip) { case USB_RECIP_DEVICE: handled = 1; @@ -51007,7 +764,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget_ep0.c linux-2.6.30.10-ubi case USB_DEVICE_REMOTE_WAKEUP: musb->may_wakeup = 1; break; -@@ -374,8 +374,8 @@ +@@ -374,8 +374,8 @@ stall: if (epnum == 0 || epnum >= MUSB_C_NUM_EPS @@ -51018,10 +775,9 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_gadget_ep0.c linux-2.6.30.10-ubi break; ep = musb->endpoints + epnum; -diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drivers/usb/musb/musb_host.c ---- linux-2.6.30.10/drivers/usb/musb/musb_host.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/musb_host.c 2009-12-11 11:45:20.000000000 +0200 -@@ -160,7 +160,11 @@ +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -160,7 +160,11 @@ static inline void musb_h_tx_start(struc /* NOTE: no locks here; caller should lock and select EP */ if (ep->epnum) { txcsr = musb_readw(ep->regs, MUSB_TXCSR); @@ -51033,7 +789,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive musb_writew(ep->regs, MUSB_TXCSR, txcsr); } else { txcsr = MUSB_CSR0_H_SETUPPKT | MUSB_CSR0_TXPKTRDY; -@@ -223,6 +227,8 @@ +@@ -223,6 +227,8 @@ musb_start_urb(struct musb *musb, int is break; default: /* bulk, interrupt */ /* actual_length may be nonzero on retry paths */ @@ -51042,7 +798,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive buf = urb->transfer_buffer + urb->actual_length; len = urb->transfer_buffer_length - urb->actual_length; } -@@ -342,13 +348,13 @@ +@@ -342,13 +348,13 @@ musb_save_toggle(struct musb_hw_ep *ep, if (!is_in) { csr = musb_readw(epio, MUSB_TXCSR); usb_settoggle(udev, qh->epnum, 1, @@ -51060,7 +816,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive } } -@@ -556,7 +562,11 @@ +@@ -556,7 +562,11 @@ musb_host_packet_rx(struct musb *musb, s musb_read_fifo(hw_ep, length, buf); csr = musb_readw(epio, MUSB_RXCSR); @@ -51072,7 +828,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive if (unlikely(do_flush)) musb_h_flush_rxfifo(hw_ep, csr); else { -@@ -590,6 +600,7 @@ +@@ -590,6 +600,7 @@ musb_rx_reinit(struct musb *musb, struct /* if programmed for Tx, put it in RX mode */ if (ep->is_shared_fifo) { @@ -51080,7 +836,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive csr = musb_readw(ep->regs, MUSB_TXCSR); if (csr & MUSB_TXCSR_MODE) { musb_h_tx_flush_fifo(ep); -@@ -604,7 +615,18 @@ +@@ -604,7 +615,18 @@ musb_rx_reinit(struct musb *musb, struct */ if (csr & MUSB_TXCSR_DMAMODE) musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE); @@ -51099,7 +855,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive /* scrub all previous state, clearing toggle */ } else { -@@ -1138,8 +1160,18 @@ +@@ -1138,8 +1160,18 @@ void musb_host_tx(struct musb *musb, u8 void __iomem *mbase = musb->mregs; struct dma_channel *dma; @@ -51118,7 +874,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive musb_ep_select(mbase, epnum); tx_csr = musb_readw(epio, MUSB_TXCSR); -@@ -1180,9 +1212,14 @@ +@@ -1180,9 +1212,14 @@ void musb_host_tx(struct musb *musb, u8 * we have a candidate... NAKing is *NOT* an error */ musb_ep_select(mbase, epnum); @@ -51133,7 +889,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive return; } -@@ -1353,8 +1390,14 @@ +@@ -1353,8 +1390,14 @@ void musb_host_tx(struct musb *musb, u8 qh->segsize = length; musb_ep_select(mbase, epnum); @@ -51149,7 +905,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive } -@@ -1414,7 +1457,11 @@ +@@ -1414,7 +1457,11 @@ static void musb_bulk_rx_nak_timeout(str /* clear nak timeout bit */ rx_csr = musb_readw(epio, MUSB_RXCSR); @@ -51161,7 +917,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive rx_csr &= ~MUSB_RXCSR_DATAERROR; musb_writew(epio, MUSB_RXCSR, rx_csr); -@@ -1483,6 +1530,13 @@ +@@ -1483,6 +1530,13 @@ void musb_host_rx(struct musb *musb, u8 pipe = urb->pipe; @@ -51175,7 +931,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive DBG(5, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n", epnum, rx_csr, urb->actual_length, dma ? dma->actual_len : 0); -@@ -1521,8 +1575,15 @@ +@@ -1521,8 +1575,15 @@ void musb_host_rx(struct musb *musb, u8 return; } musb_ep_select(mbase, epnum); @@ -51191,7 +947,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive musb_writew(epio, MUSB_RXCSR, rx_csr); goto finish; -@@ -1579,8 +1640,13 @@ +@@ -1579,8 +1640,13 @@ void musb_host_rx(struct musb *musb, u8 rx_csr &= ~MUSB_RXCSR_H_REQPKT; musb_ep_select(mbase, epnum); @@ -51205,7 +961,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive } #endif if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) { -@@ -1610,7 +1676,7 @@ +@@ -1610,7 +1676,7 @@ void musb_host_rx(struct musb *musb, u8 else done = false; @@ -51214,7 +970,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive /* done if urb buffer is full or short packet is recd */ done = (urb->actual_length + xfer_len >= urb->transfer_buffer_length -@@ -1823,7 +1889,11 @@ +@@ -1823,7 +1889,11 @@ static int musb_schedule( } else if (hw_ep->out_qh != NULL) continue; @@ -51226,7 +982,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive continue; if (is_in) -@@ -1836,7 +1906,14 @@ +@@ -1836,7 +1906,14 @@ static int musb_schedule( best_end = epnum; } } @@ -51241,7 +997,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) { hw_ep = musb->bulk_ep; if (is_in) -@@ -1858,6 +1935,22 @@ +@@ -1858,6 +1935,22 @@ static int musb_schedule( } else if (best_end < 0) { return -ENOSPC; } @@ -51264,7 +1020,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive idle = 1; qh->mux = 0; -@@ -1869,6 +1962,13 @@ +@@ -1869,6 +1962,13 @@ success: list_add_tail(&qh->ring, head); qh->mux = 1; } @@ -51278,7 +1034,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive qh->hw_ep = hw_ep; qh->hep->hcpriv = qh; if (idle) -@@ -1975,6 +2075,15 @@ +@@ -1975,6 +2075,15 @@ static int musb_urb_enqueue( /* ISO always uses logarithmic encoding */ interval = min_t(u8, epd->bInterval, 16); break; @@ -51294,10 +1050,9 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_host.c linux-2.6.30.10-ubi/drive default: /* REVISIT we actually want to use NAK limits, hinting to the * transfer scheduling logic to try some other qh, e.g. try -diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_io.h linux-2.6.30.10-ubi/drivers/usb/musb/musb_io.h ---- linux-2.6.30.10/drivers/usb/musb/musb_io.h 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/musb_io.h 2009-12-11 11:45:20.000000000 +0200 -@@ -58,6 +58,7 @@ +--- a/drivers/usb/musb/musb_io.h ++++ b/drivers/usb/musb/musb_io.h +@@ -58,6 +58,7 @@ static inline void writesb(const void __ #ifndef CONFIG_BLACKFIN @@ -51305,7 +1060,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_io.h linux-2.6.30.10-ubi/drivers /* NOTE: these offsets are all in bytes */ static inline u16 musb_readw(const void __iomem *addr, unsigned offset) -@@ -72,7 +73,37 @@ +@@ -72,7 +73,37 @@ static inline void musb_writew(void __io static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) { __raw_writel(data, addr + offset); } @@ -51343,7 +1098,7 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_io.h linux-2.6.30.10-ubi/drivers #ifdef CONFIG_USB_TUSB6010 -@@ -106,7 +137,7 @@ +@@ -106,7 +137,7 @@ static inline void musb_writeb(void __io __raw_writew(tmp, addr + (offset & ~1)); } @@ -51352,9 +1107,8 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_io.h linux-2.6.30.10-ubi/drivers static inline u8 musb_readb(const void __iomem *addr, unsigned offset) { return __raw_readb(addr + offset); } -diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_regs.h linux-2.6.30.10-ubi/drivers/usb/musb/musb_regs.h ---- linux-2.6.30.10/drivers/usb/musb/musb_regs.h 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/musb_regs.h 2009-12-11 11:45:20.000000000 +0200 +--- a/drivers/usb/musb/musb_regs.h ++++ b/drivers/usb/musb/musb_regs.h @@ -167,6 +167,7 @@ (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \ | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY) @@ -51363,170 +1117,9 @@ diff -ruN linux-2.6.30.10/drivers/usb/musb/musb_regs.h linux-2.6.30.10-ubi/drive /* RXCSR in Peripheral and Host mode */ #define MUSB_RXCSR_AUTOCLEAR 0x8000 #define MUSB_RXCSR_DMAENAB 0x2000 -diff -ruN linux-2.6.30.10/drivers/usb/musb/ubi32_usb.c linux-2.6.30.10-ubi/drivers/usb/musb/ubi32_usb.c ---- linux-2.6.30.10/drivers/usb/musb/ubi32_usb.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/usb/musb/ubi32_usb.c 2009-12-11 11:45:20.000000000 +0200 -@@ -0,0 +1,156 @@ -+/* -+ * drivers/usb/musb/ubi32_usb.c -+ * Ubicom32 usb controller driver. -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * Copyright (C) 2005-2006 by Texas Instruments -+ * -+ * Derived from the Texas Instruments Inventra Controller Driver for Linux. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "musb_core.h" -+ -+void musb_platform_enable(struct musb *musb) -+{ -+} -+void musb_platform_disable(struct musb *musb) -+{ -+} -+ -+int musb_platform_set_mode(struct musb *musb, u8 musb_mode) { -+ return 0; -+} -+ -+static void ip5k_usb_hcd_vbus_power(struct musb *musb, int is_on, int sleeping) -+{ -+} -+ -+static void ip5k_usb_hcd_set_vbus(struct musb *musb, int is_on) -+{ -+ u8 devctl; -+ /* HDRC controls CPEN, but beware current surges during device -+ * connect. They can trigger transient overcurrent conditions -+ * that must be ignored. -+ */ -+ -+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL); -+ -+ if (is_on) { -+ musb->is_active = 1; -+ musb->xceiv.default_a = 1; -+ musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; -+ devctl |= MUSB_DEVCTL_SESSION; -+ -+ MUSB_HST_MODE(musb); -+ } else { -+ musb->is_active = 0; -+ -+ /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and -+ * jumping right to B_IDLE... -+ */ -+ -+ musb->xceiv.default_a = 0; -+ musb->xceiv.state = OTG_STATE_B_IDLE; -+ devctl &= ~MUSB_DEVCTL_SESSION; -+ -+ MUSB_DEV_MODE(musb); -+ } -+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); -+ -+ DBG(1, "VBUS %s, devctl %02x " -+ /* otg %3x conf %08x prcm %08x */ "\n", -+ otg_state_string(musb), -+ musb_readb(musb->mregs, MUSB_DEVCTL)); -+} -+static int ip5k_usb_hcd_set_power(struct otg_transceiver *x, unsigned mA) -+{ -+ return 0; -+} -+ -+static int musb_platform_resume(struct musb *musb); -+ -+int __init musb_platform_init(struct musb *musb) -+{ -+ -+#ifdef CONFIG_UBICOM32_V4 -+ u32_t chip_id; -+ asm volatile ( -+ "move.4 %0, CHIP_ID \n\t" -+ : "=r" (chip_id) -+ ); -+ if (chip_id == 0x30001) { -+ *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 30); -+ udelay(1); -+ *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 31); -+ } else { -+ *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 17); -+ udelay(1); -+ *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 14); -+ } -+#endif -+ -+ *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_CFG)) |= ((1 << 14) | (1 <<15)); -+ -+ /* The i-clk is AUTO gated. Hence there is no need -+ * to disable it until the driver is shutdown */ -+ -+ clk_enable(musb->clock); -+ musb_platform_resume(musb); -+ -+ ip5k_usb_hcd_vbus_power(musb, musb->board_mode == MUSB_HOST, 1); -+ -+ if (is_host_enabled(musb)) -+ musb->board_set_vbus = ip5k_usb_hcd_set_vbus; -+ if (is_peripheral_enabled(musb)) -+ musb->xceiv.set_power = ip5k_usb_hcd_set_power; -+ -+ return 0; -+} -+ -+ -+int musb_platform_suspend(struct musb *musb) -+{ -+ return 0; -+} -+int musb_platform_resume(struct musb *musb) -+{ -+ return 0; -+} -+ -+int musb_platform_exit(struct musb *musb) -+{ -+ ip5k_usb_hcd_vbus_power(musb, 0 /*off*/, 1); -+ musb_platform_suspend(musb); -+ return 0; -+} -diff -ruN linux-2.6.30.10/drivers/video/backlight/Kconfig linux-2.6.30.10-ubi/drivers/video/backlight/Kconfig ---- linux-2.6.30.10/drivers/video/backlight/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/backlight/Kconfig 2009-12-11 11:45:20.000000000 +0200 -@@ -93,6 +93,63 @@ +--- a/drivers/video/backlight/Kconfig ++++ b/drivers/video/backlight/Kconfig +@@ -93,6 +93,63 @@ config LCD_HP700 If you have an HP Jornada 700 series handheld (710/720/728) say Y to enable LCD control driver. @@ -51590,7 +1183,7 @@ diff -ruN linux-2.6.30.10/drivers/video/backlight/Kconfig linux-2.6.30.10-ubi/dr # # Backlight # -@@ -229,3 +286,11 @@ +@@ -229,3 +286,11 @@ config BACKLIGHT_SAHARA help If you have a Tabletkiosk Sahara Touch-iT, say y to enable the backlight driver. @@ -51602,10 +1195,9 @@ diff -ruN linux-2.6.30.10/drivers/video/backlight/Kconfig linux-2.6.30.10-ubi/dr + help + If you have a Ubicom32 based system with a backlight say Y to enable the + backlight driver. -diff -ruN linux-2.6.30.10/drivers/video/backlight/Makefile linux-2.6.30.10-ubi/drivers/video/backlight/Makefile ---- linux-2.6.30.10/drivers/video/backlight/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/backlight/Makefile 2009-12-11 11:45:20.000000000 +0200 -@@ -9,6 +9,9 @@ +--- a/drivers/video/backlight/Makefile ++++ b/drivers/video/backlight/Makefile +@@ -9,6 +9,9 @@ obj-$(CONFIG_LCD_PLATFORM) += platfor obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o obj-$(CONFIG_LCD_TDO24M) += tdo24m.o obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o @@ -51615,1543 +1207,15 @@ diff -ruN linux-2.6.30.10/drivers/video/backlight/Makefile linux-2.6.30.10-ubi/d obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o -@@ -24,4 +27,4 @@ +@@ -24,4 +27,4 @@ obj-$(CONFIG_BACKLIGHT_DA903X) += da903x obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o - +obj-$(CONFIG_BACKLIGHT_UBICOM32) += ubicom32bl.o -diff -ruN linux-2.6.30.10/drivers/video/backlight/ubicom32bl.c linux-2.6.30.10-ubi/drivers/video/backlight/ubicom32bl.c ---- linux-2.6.30.10/drivers/video/backlight/ubicom32bl.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/backlight/ubicom32bl.c 2009-12-11 11:45:20.000000000 +0200 -@@ -0,0 +1,399 @@ -+/* -+ * drivers/video/backlight/ubicom32bl.c -+ * Backlight driver for the Ubicom32 platform -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define DRIVER_NAME "ubicom32bl" -+#define UBICOM32BL_MAX_BRIGHTNESS 255 -+ -+struct ubicom32bl_data { -+ /* -+ * Pointer to the platform data structure. Keep this around since we need values -+ * from it to set the backlight intensity. -+ */ -+ const struct ubicom32bl_platform_data *pdata; -+ -+ /* -+ * Backlight device, we have to save this for use when we remove ourselves. -+ */ -+ struct backlight_device *bldev; -+ -+ /* -+ * Current intensity, used for get_intensity. -+ */ -+ int cur_intensity; -+ -+ /* -+ * Init function for PWM -+ */ -+ int (*init_fn)(struct ubicom32bl_data *); -+ -+ /* -+ * Set intensity function depending on the backlight type -+ */ -+ int (*set_intensity_fn)(struct ubicom32bl_data *, int); -+}; -+ -+/* -+ * ubicom32bl_set_intensity_gpio -+ */ -+static int ubicom32bl_set_intensity_gpio(struct ubicom32bl_data *ud, int intensity) -+{ -+ ud->cur_intensity = intensity ? 255 : 0; -+ -+ if (intensity) { -+ // set gpio -+ return 0; -+ } -+ -+ // clear gpio -+ return 0; -+} -+ -+/* -+ * ubicom32bl_set_intensity_hw -+ */ -+static int ubicom32bl_set_intensity_hw(struct ubicom32bl_data *ud, int intensity) -+{ -+ u16_t period = ud->pdata->pwm_period; -+ u16_t duty; -+ -+ /* -+ * Calculate the new duty cycle -+ */ -+ duty = (period * intensity) / (UBICOM32BL_MAX_BRIGHTNESS + 1); -+ -+ /* -+ * Set the new duty cycle -+ */ -+ switch (ud->pdata->pwm_channel) { -+ case 0: -+ /* -+ * Channel 0 is in the lower half of PORT C ctl0 and ctl1 -+ */ -+ UBICOM32_IO_PORT(RC)->ctl1 = (ud->pdata->pwm_period << 16) | duty; -+ break; -+ -+ case 1: -+ /* -+ * Channel 1 is in the upper half of PORT C ctl0 and ctl2 -+ */ -+ UBICOM32_IO_PORT(RC)->ctl2 = (ud->pdata->pwm_period << 16) | duty; -+ break; -+ -+ case 2: -+ /* -+ * Channel 2 is in PORT H ctl0 and ctl1 -+ */ -+ UBICOM32_IO_PORT(RH)->ctl1 = (ud->pdata->pwm_period << 16) | duty; -+ break; -+ } -+ -+ ud->cur_intensity = intensity; -+ -+ return 0; -+} -+ -+/* -+ * ubicom32bl_set_intensity -+ */ -+static int ubicom32bl_set_intensity(struct backlight_device *bd) -+{ -+ struct ubicom32bl_data *ud = (struct ubicom32bl_data *)bl_get_data(bd); -+ int intensity = bd->props.brightness; -+ -+ /* -+ * If we're blanked the the intensity doesn't matter. -+ */ -+ if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) { -+ intensity = 0; -+ } -+ -+ /* -+ * Check for inverted backlight. -+ */ -+ if (ud->pdata->invert) { -+ intensity = UBICOM32BL_MAX_BRIGHTNESS - intensity; -+ } -+ -+ if (ud->set_intensity_fn) { -+ return ud->set_intensity_fn(ud, intensity); -+ } -+ -+ return -ENXIO; -+} -+ -+/* -+ * ubicom32bl_get_intensity -+ * Return the current intensity of the backlight. -+ */ -+static int ubicom32bl_get_intensity(struct backlight_device *bd) -+{ -+ struct ubicom32bl_data *ud = (struct ubicom32bl_data *)bl_get_data(bd); -+ -+ return ud->cur_intensity; -+} -+ -+/* -+ * ubicom32bl_init_hw_pwm -+ * Set the appropriate PWM registers -+ */ -+static int ubicom32bl_init_hw_pwm(struct ubicom32bl_data *ud) -+{ -+ /* -+ * bit 13: enable -+ */ -+ u16_t pwm_cfg = (1 << 13) | (ud->pdata->pwm_prescale << 8) ; -+ -+ switch (ud->pdata->pwm_channel) { -+ case 0: -+ /* -+ * Channel 0 is in the lower half of PORT C ctl0 and ctl1 (PA5) -+ */ -+ UBICOM32_IO_PORT(RC)->ctl0 &= ~0xFFFF; -+ UBICOM32_IO_PORT(RC)->ctl0 |= pwm_cfg; -+ UBICOM32_IO_PORT(RC)->ctl1 = ud->pdata->pwm_period << 16; -+ -+ /* -+ * If the port function is not set, set it to GPIO/PWM -+ */ -+ if (!UBICOM32_IO_PORT(RA)->function) { -+ UBICOM32_IO_PORT(RA)->function = 3; -+ } -+ break; -+ -+ case 1: -+ /* -+ * Channel 1 is in the upper half of PORT C ctl0 and ctl2 (PE4) -+ */ -+ UBICOM32_IO_PORT(RC)->ctl0 &= ~0xFFFF0000; -+ UBICOM32_IO_PORT(RC)->ctl0 |= (pwm_cfg << 16); -+ UBICOM32_IO_PORT(RC)->ctl2 = ud->pdata->pwm_period << 16; -+ -+ /* -+ * If the port function is not set, set it to GPIO/ExtIOInt -+ */ -+ if (!UBICOM32_IO_PORT(RE)->function) { -+ UBICOM32_IO_PORT(RE)->function = 3; -+ } -+ break; -+ -+ case 2: -+ /* -+ * Channel 2 is in PORT H ctl0 and ctl1 (PD0) -+ */ -+ UBICOM32_IO_PORT(RH)->ctl0 &= ~0xFFFF0000; -+ UBICOM32_IO_PORT(RH)->ctl0 = pwm_cfg; -+ UBICOM32_IO_PORT(RH)->ctl1 = ud->pdata->pwm_period << 16; -+ -+ /* -+ * If the port function is not set, set it to GPIO -+ */ -+ if (!UBICOM32_IO_PORT(RD)->function) { -+ UBICOM32_IO_PORT(RD)->function = 3; -+ } -+ break; -+ } -+ -+ return 0; -+} -+ -+/* -+ * ubicom32bl_init_gpio -+ * Allocate the appropriate GPIO -+ */ -+static int ubicom32bl_init_gpio(struct ubicom32bl_data *ud) -+{ -+ return 0; -+} -+ -+static struct backlight_ops ubicom32bl_ops = { -+ .get_brightness = ubicom32bl_get_intensity, -+ .update_status = ubicom32bl_set_intensity, -+}; -+ -+/* -+ * ubicom32bl_probe -+ */ -+static int ubicom32bl_probe(struct platform_device *pdev) -+{ -+ const struct ubicom32bl_platform_data *pdata = pdev->dev.platform_data; -+ struct ubicom32bl_data *ud; -+ struct backlight_device *bldev; -+ int retval; -+ -+ /* -+ * Check to see if we have any platform data, if we don't then the backlight is not -+ * configured on this device. -+ */ -+ if (!pdata) { -+ return -ENODEV; -+ } -+ -+ /* -+ * Allocate our private data -+ */ -+ ud = kzalloc(sizeof(struct ubicom32bl_data), GFP_KERNEL); -+ if (!ud) { -+ return -ENOMEM; -+ } -+ -+ ud->pdata = pdata; -+ -+ /* -+ * Check to see that the platform data is valid for this driver -+ */ -+ switch (pdata->type) { -+ case UBICOM32BL_TYPE_PWM: -+ { -+ /* -+ * Make sure we have a PWM peripheral -+ */ -+ u32_t chipid; -+ asm volatile ( -+ "move.4 %0, CHIP_ID \n\t" -+ : "=r" (chipid) -+ ); -+ if (chipid != 0x00030001) { -+ retval = -ENODEV; -+ goto fail; -+ } -+ -+ if (pdata->pwm_channel > 3) { -+ retval = -ENODEV; -+ goto fail; -+ } -+ if (pdata->pwm_prescale > 16) { -+ retval = -EINVAL; -+ goto fail; -+ } -+ -+ ud->init_fn = ubicom32bl_init_hw_pwm; -+ ud->set_intensity_fn = ubicom32bl_set_intensity_hw; -+ break; -+ } -+ -+ case UBICOM32BL_TYPE_PWM_HRT: -+ // For now, PWM HRT devices are treated as binary lights. -+ -+ case UBICOM32BL_TYPE_BINARY: -+ ud->init_fn = ubicom32bl_init_gpio; -+ ud->set_intensity_fn = ubicom32bl_set_intensity_gpio; -+ break; -+ } -+ -+ /* -+ * Register our backlight device -+ */ -+ bldev = backlight_device_register(DRIVER_NAME, &pdev->dev, ud, &ubicom32bl_ops); -+ if (IS_ERR(bldev)) { -+ retval = PTR_ERR(bldev); -+ goto fail; -+ } -+ -+ ud->bldev = bldev; -+ ud->cur_intensity = pdata->default_intensity; -+ platform_set_drvdata(pdev, ud); -+ -+ /* -+ * Start up the backlight at the prescribed default intensity -+ */ -+ bldev->props.power = FB_BLANK_UNBLANK; -+ bldev->props.max_brightness = UBICOM32BL_MAX_BRIGHTNESS; -+ bldev->props.brightness = pdata->default_intensity; -+ -+ if (ud->init_fn) { -+ if (ud->init_fn(ud) != 0) { -+ retval = -ENODEV; -+ backlight_device_unregister(ud->bldev); -+ goto fail; -+ } -+ } -+ ubicom32bl_set_intensity(bldev); -+ -+ printk(KERN_INFO DRIVER_NAME ": Backlight driver started\n"); -+ -+ return 0; -+ -+fail: -+ platform_set_drvdata(pdev, NULL); -+ kfree(ud); -+ return retval; -+} -+ -+/* -+ * ubicom32bl_remove -+ */ -+static int __exit ubicom32bl_remove(struct platform_device *pdev) -+{ -+ struct ubicom32bl_data *ud = platform_get_drvdata(pdev); -+ -+ backlight_device_unregister(ud->bldev); -+ platform_set_drvdata(pdev, NULL); -+ kfree(ud); -+ -+ return 0; -+} -+ -+static struct platform_driver ubicom32bl_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ -+ .remove = __exit_p(ubicom32bl_remove), -+}; -+ -+/* -+ * ubicom32bl_init -+ */ -+static int __init ubicom32bl_init(void) -+{ -+ return platform_driver_probe(&ubicom32bl_driver, ubicom32bl_probe); -+} -+module_init(ubicom32bl_init); -+ -+/* -+ * ubicom32bl_exit -+ */ -+static void __exit ubicom32bl_exit(void) -+{ -+ platform_driver_unregister(&ubicom32bl_driver); -+} -+module_exit(ubicom32bl_exit); -+ -+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); -+MODULE_DESCRIPTION("Ubicom32 backlight driver"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/drivers/video/backlight/ubicom32lcd.c linux-2.6.30.10-ubi/drivers/video/backlight/ubicom32lcd.c ---- linux-2.6.30.10/drivers/video/backlight/ubicom32lcd.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/backlight/ubicom32lcd.c 2009-12-11 11:45:20.000000000 +0200 -@@ -0,0 +1,372 @@ -+/* -+ * drivers/video/ubicom32lcd.c -+ * LCD initilization code -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ubicom32lcd.h" -+ -+#define DRIVER_NAME "ubicom32lcd" -+ -+struct ubicom32lcd_data { -+ const struct ubicom32lcd_panel *panel; -+ -+ int pin_cs; -+ int pin_rd; -+ int pin_rs; -+ int pin_wr; -+ int pin_reset; -+ struct ubicom32_io_port *port_data; -+ int data_shift; -+}; -+ -+/* -+ * ubicom32lcd_write -+ * Performs a write cycle on the bus (assumes CS asserted, RD & WR set) -+ */ -+static void ubicom32lcd_write(struct ubicom32lcd_data *ud, int command, u16 data) -+{ -+ if (command) { -+ UBICOM32_GPIO_SET_PIN_LOW(ud->pin_rs); -+ } else { -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs); -+ } -+ -+ asm volatile ( -+ "or.4 4(%[port]), 4(%[port]), %[mask] \n\t" -+ "not.4 %[mask], %[mask] \n\t" -+ "and.4 8(%[port]), 8(%[port]), %[mask] \n\t" -+ "or.4 8(%[port]), 8(%[port]), %[cmd] \n\t" -+ : -+ : [port] "a" (ud->port_data), -+ [mask] "d" (0xFFFF << ud->data_shift), -+ [cmd] "d" (data << ud->data_shift) -+ : "cc" -+ ); -+ -+ UBICOM32_GPIO_SET_PIN_LOW(ud->pin_wr); -+ -+ //ndelay(50); -+ udelay(1); -+ -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr); -+ -+ udelay(1); -+ //ndelay(50); -+} -+ -+/* -+ * ubicom32lcd_read_data -+ * Performs a read cycle on the bus (assumes CS asserted, RD & WR set) -+ */ -+static u16 ubicom32lcd_read_data(struct ubicom32lcd_data *ud) -+{ -+ u32_t data; -+ -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs); -+ -+ asm volatile ( -+ "and.4 4(%[port]), 4(%[port]), %[mask]\n\t" -+ : -+ : [port] "a" (ud->port_data), -+ [mask] "d" (~(0xFFFF << ud->data_shift)) -+ : "cc" -+ ); -+ -+ UBICOM32_GPIO_SET_PIN_LOW(ud->pin_rd); -+ -+ ndelay(300); -+ -+ asm volatile ( -+ "lsr.4 %[data], 12(%[port]), %[shamt] \n\t" -+ "and.4 %[data], %[data], %[mask] \n\t" -+ : [data] "=d" (data) -+ : [port] "a" (ud->port_data), -+ [mask] "d" (0xFFFF), -+ [shamt] "d" (ud->data_shift) -+ : "cc" -+ ); -+ -+ ndelay(200); -+ -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd); -+ -+ ndelay(500); -+ -+ return data; -+} -+ -+/* -+ * ubicom32lcd_execute -+ * Executes a script for performing operations on the LCD (assumes CS set) -+ */ -+static void ubicom32lcd_execute(struct ubicom32lcd_data *ud, const struct ubicom32lcd_step *script) -+{ -+ while (1) { -+ switch (script->op) { -+ case LCD_STEP_CMD: -+ ubicom32lcd_write(ud, 1, script->cmd); -+ break; -+ -+ case LCD_STEP_DATA: -+ ubicom32lcd_write(ud, 0, script->data); -+ break; -+ -+ case LCD_STEP_CMD_DATA: -+ ubicom32lcd_write(ud, 1, script->cmd); -+ ubicom32lcd_write(ud, 0, script->data); -+ break; -+ -+ case LCD_STEP_SLEEP: -+ udelay(script->data); -+ break; -+ -+ case LCD_STEP_DONE: -+ return; -+ } -+ script++; -+ } -+} -+ -+/* -+ * ubicom32lcd_goto -+ * Places the gram pointer at a specific X, Y address -+ */ -+static void ubicom32lcd_goto(struct ubicom32lcd_data *ud, int x, int y) -+{ -+ ubicom32lcd_write(ud, 1, ud->panel->horz_reg); -+ ubicom32lcd_write(ud, 0, x); -+ ubicom32lcd_write(ud, 1, ud->panel->vert_reg); -+ ubicom32lcd_write(ud, 0, y); -+ ubicom32lcd_write(ud, 1, ud->panel->gram_reg); -+} -+ -+/* -+ * ubicom32lcd_panel_init -+ * Initializes the lcd panel. -+ */ -+static int ubicom32lcd_panel_init(struct ubicom32lcd_data *ud) -+{ -+ u16 id; -+ -+ UBICOM32_GPIO_SET_PIN_LOW(ud->pin_reset); -+ UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_reset); -+ UBICOM32_GPIO_ENABLE(ud->pin_reset); -+ -+ asm volatile ( -+ "or.4 0x50(%[port]), 0x50(%[port]), %[mask] \n\t" -+ "not.4 %[mask], %[mask] \n\t" -+ "and.4 0x04(%[port]), 0x04(%[port]), %[mask] \n\t" -+ : -+ : [port] "a" (ud->port_data), -+ [mask] "d" (0xFFFF << ud->data_shift) -+ : "cc" -+ ); -+ -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs); -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd); -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr); -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs); -+ -+ UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_rs); -+ UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_rd); -+ UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_wr); -+ UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_cs); -+ -+ UBICOM32_GPIO_ENABLE(ud->pin_rs); -+ UBICOM32_GPIO_ENABLE(ud->pin_rd); -+ UBICOM32_GPIO_ENABLE(ud->pin_wr); -+ UBICOM32_GPIO_ENABLE(ud->pin_cs); -+ -+ udelay(20); -+ -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_reset); -+ -+ udelay(20); -+ -+ UBICOM32_GPIO_SET_PIN_LOW(ud->pin_cs); -+ -+ id = ubicom32lcd_read_data(ud); -+ -+ /* -+ * We will try to figure out what kind of panel we have if we were not told. -+ */ -+ if (!ud->panel) { -+ const struct ubicom32lcd_panel **p = ubicom32lcd_panels; -+ while (*p) { -+ if ((*p)->id && ((*p)->id == id)) { -+ break; -+ } -+ p++; -+ } -+ if (!*p) { -+ printk(KERN_WARNING DRIVER_NAME ":Could not find compatible panel, id=%x\n", id); -+ return -ENODEV; -+ } -+ ud->panel = *p; -+ } -+ -+ /* -+ * Make sure panel ID matches if we were supplied a panel type -+ */ -+ if (ud->panel->id && (ud->panel->id != id)) { -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs); -+ -+ return -ENODEV; -+ } -+ -+ ubicom32lcd_execute(ud, ud->panel->init_seq); -+ -+ ubicom32lcd_goto(ud, 0, 0); -+ -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs); -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd); -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr); -+ UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs); -+ -+ printk(KERN_INFO DRIVER_NAME ": Initialized panel %s\n", ud->panel->desc); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32lcd_probe -+ */ -+static int ubicom32lcd_probe(struct platform_device *pdev) -+{ -+ const struct ubicom32lcd_platform_data *pdata = pdev->dev.platform_data; -+ struct ubicom32lcd_data *ud; -+ int retval; -+ -+ /* -+ * Allocate our private data -+ */ -+ ud = kzalloc(sizeof(struct ubicom32lcd_data), GFP_KERNEL); -+ if (!ud) { -+ return -ENOMEM; -+ } -+ -+ if (pdata) { -+ ud->pin_cs = pdata->pin_cs; -+ ud->pin_rd = pdata->pin_rd; -+ ud->pin_wr = pdata->pin_wr; -+ ud->pin_rs = pdata->pin_rs; -+ ud->pin_reset = pdata->pin_reset; -+ ud->port_data = pdata->port_data; -+ ud->data_shift = pdata->data_shift; -+ } else { -+ /* -+ * Defaults -+ */ -+ ud->pin_cs = GPIO_RD_4; -+ ud->pin_rd = GPIO_RD_5; -+ ud->pin_rs = GPIO_RD_3; -+ ud->pin_wr = GPIO_RD_2; -+ ud->pin_reset = GPIO_RD_7; -+ ud->port_data = (struct ubicom32_io_port *)RI; -+ ud->data_shift = 0; -+ } -+ -+ /* -+ * Initialize the display -+ */ -+ retval = ubicom32lcd_panel_init(ud); -+ if (retval) { -+ kfree(ud); -+ return retval; -+ } -+ -+ printk(KERN_INFO DRIVER_NAME ": LCD initialized\n"); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32lcd_remove -+ */ -+static int __exit ubicom32lcd_remove(struct platform_device *pdev) -+{ -+ struct ubicom32lcd_data *ud = platform_get_drvdata(pdev); -+ -+ kfree(ud); -+ -+ return 0; -+} -+ -+static struct platform_driver ubicom32lcd_driver = { -+ .probe = ubicom32lcd_probe, -+ .remove = ubicom32lcd_remove, -+ -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ -+ .remove = __exit_p(ubicom32lcd_remove), -+}; -+ -+static struct platform_device *ubicom32lcd_device; -+ -+/* -+ * ubicom32lcd_init -+ */ -+static int __init ubicom32lcd_init(void) -+{ -+ int res; -+ -+ res = platform_driver_register(&ubicom32lcd_driver); -+ if (res == 0) { -+ ubicom32lcd_device = platform_device_alloc(DRIVER_NAME, 0); -+ if (ubicom32lcd_device) { -+ res = platform_device_add(ubicom32lcd_device); -+ } else { -+ res = -ENOMEM; -+ } -+ if (res) { -+ platform_device_put(ubicom32lcd_device); -+ platform_driver_unregister(&ubicom32lcd_driver); -+ } -+ } -+ return res; -+} -+module_init(ubicom32lcd_init); -+ -+/* -+ * ubicom32lcd_exit -+ */ -+static void __exit ubicom32lcd_exit(void) -+{ -+ platform_device_unregister(ubicom32lcd_device); -+ platform_driver_unregister(&ubicom32lcd_driver); -+} -+module_exit(ubicom32lcd_exit); -+ -+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); -+MODULE_DESCRIPTION("Ubicom32 LCD driver"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/drivers/video/backlight/ubicom32lcd.h linux-2.6.30.10-ubi/drivers/video/backlight/ubicom32lcd.h ---- linux-2.6.30.10/drivers/video/backlight/ubicom32lcd.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/backlight/ubicom32lcd.h 2009-12-11 11:45:20.000000000 +0200 -@@ -0,0 +1,546 @@ -+/* -+ * ubicom32lcd.h -+ * Ubicom32 lcd panel drivers -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * This Ubicom32 library is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * This Ubicom32 library is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#ifndef _UBICOM32LCD_H_ -+#define _UBICOM32LCD_H_ -+ -+enum ubicom32lcd_op { -+ /* -+ * Sleep for (data) ms -+ */ -+ LCD_STEP_SLEEP, -+ -+ /* -+ * Execute write of command -+ */ -+ LCD_STEP_CMD, -+ -+ /* -+ * Execute write of data -+ */ -+ LCD_STEP_DATA, -+ -+ /* -+ * Execute write of command/data -+ */ -+ LCD_STEP_CMD_DATA, -+ -+ /* -+ * Script done -+ */ -+ LCD_STEP_DONE, -+}; -+ -+struct ubicom32lcd_step { -+ enum ubicom32lcd_op op; -+ u16 cmd; -+ u16 data; -+}; -+ -+struct ubicom32lcd_panel { -+ const struct ubicom32lcd_step *init_seq; -+ const char *desc; -+ -+ u32 xres; -+ u32 yres; -+ u32 stride; -+ u32 flags; -+ -+ u16 id; -+ u16 horz_reg; -+ u16 vert_reg; -+ u16 gram_reg; -+}; -+ -+#ifdef CONFIG_LCD_UBICOM32_CFAF240320KTTS -+static const struct ubicom32lcd_step cfaf240320ktts_init_0[] = { -+ {LCD_STEP_CMD_DATA, 0x0001, 0x0000,}, // Driver Output Control Register (R01h) Page 14, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0002, 0x0700,}, // LCD Driving Waveform Control (R02h) Page 15, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0003, 0x50A0,}, // Entry Mode (R03h) 0 degrees -+ {LCD_STEP_CMD_DATA, 0x0004, 0x0000,}, // Scaling Control register (R04h) Page 16, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0008, 0x0207,}, // Display Control 2 (R08h) Page 17, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0009, 0x0000,}, // Display Control 3 (R09h) Page 18, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x000A, 0x0000,}, // Frame Cycle Control (R0Ah) Page 19, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x000C, 0x0000,}, // External Display Interface Control 1 (R0Ch) Page 20, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x000D, 0x0000,}, // Frame Maker Position (R0Dh) Page 21, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x000F, 0x0000,}, // External Display Interface Control 2 (R0Fh) Page 21, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0010, 0x0000,}, // Power Control 1 (R10h) Page 22, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h) Page 23, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0012, 0x0000,}, // Power Control 3 (R12h) Page 24, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0013, 0x0000,}, // Power Control 4 (R13h) Page 25, SPFD5408B Datasheet -+ {LCD_STEP_SLEEP, 0, 200}, -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0101,}, // Display Control (R07h) Page 16, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0010, 0x12B0,}, // Power Control 1 (R10h) Page 22, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h) Page 23, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0012, 0x01BB,}, // Power Control 3 (R12h) Page 24, SPFD5408B Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ {LCD_STEP_CMD_DATA, 0x0013, 0x1300,}, // Power Control 4 (R13h) Page 25, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0029, 0x0010,}, // NVM read data 2 (R29h) Page 30, SPFD5408B Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ {LCD_STEP_CMD_DATA, 0x0030, 0x000A,}, // Gamma Control 1 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0031, 0x1326,}, // Gamma Control 2 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0032, 0x0A29,}, // Gamma Control 3 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0033, 0x290A,}, // Gamma Control 4 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0034, 0x2613,}, // Gamma Control 5 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0035, 0x0A0A,}, // Gamma Control 6 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0036, 0x1E03,}, // Gamma Control 7 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0037, 0x031E,}, // Gamma Control 8 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0038, 0x0706,}, // Gamma Control 9 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0039, 0x0303,}, // Gamma Control 10 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003A, 0x0E04,}, // Gamma Control 11 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003B, 0x0E01,}, // Gamma Control 12 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003C, 0x010E,}, // Gamma Control 13 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003D, 0x040E,}, // Gamma Control 14 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003E, 0x0303,}, // Gamma Control 15 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003F, 0x0607,}, // Gamma Control 16 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0050, 0x0000,}, // Window Horizontal RAM Address Start (R50h) Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0051, 0x00EF,}, // Window Horizontal RAM Address End (R51h) Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0052, 0x0000,}, // Window Vertical RAM Address Start (R52h) Page 33, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0053, 0x013F,}, // Window Vertical RAM Address End (R53h) Page 33, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0060, 0x2700,}, // Driver Output Control (R60h) Page 33, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0061, 0x0001,}, // Driver Output Control (R61h) Page 35, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x006A, 0x0000,}, // Vertical Scroll Control (R6Ah) Page 35, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0080, 0x0000,}, // Display Position - Partial Display 1 (R80h) Page 35, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0081, 0x0000,}, // RAM Address Start - Partial Display 1 (R81h) Page 35, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0082, 0x0000,}, // RAM Address End - Partial Display 1 (R82h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0083, 0x0000,}, // Display Position - Partial Display 2 (R83h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0084, 0x0000,}, // RAM Address Start - Partial Display 2 (R84h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0085, 0x0000,}, // RAM Address End - Partial Display 2 (R85h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0090, 0x0010,}, // Panel Interface Control 1 (R90h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0092, 0x0000,}, // Panel Interface Control 2 (R92h) Page 37, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0093, 0x0103,}, // Panel Interface control 3 (R93h) Page 38, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0095, 0x0210,}, // Panel Interface control 4 (R95h) Page 38, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0097, 0x0000,}, // Panel Interface Control 5 (R97h) Page 40, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0098, 0x0000,}, // Panel Interface Control 6 (R98h) Page 41, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0173,}, // Display Control (R07h) Page 16, SPFD5408B Datasheet -+ {LCD_STEP_DONE, 0, 0}, -+}; -+ -+const struct ubicom32lcd_panel cfaf240320ktts_0 = { -+ .desc = "CFAF240320KTTS", -+ .init_seq = cfaf240320ktts_init_0, -+ .horz_reg = 0x20, -+ .vert_reg = 0x21, -+ .gram_reg = 0x22, -+ .xres = 240, -+ .yres = 320, -+ .stride = 240, -+ .id = 0x5408, -+}; -+#endif -+ -+#ifdef CONFIG_LCD_UBICOM32_CFAF240320KTTS_180 -+static const struct ubicom32lcd_step cfaf240320ktts_init_180[] = { -+ {LCD_STEP_CMD_DATA, 0x0001, 0x0000,}, // Driver Output Control Register (R01h) Page 14, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0002, 0x0700,}, // LCD Driving Waveform Control (R02h) Page 15, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0003, 0x5000,}, // Entry Mode (R03h) 180 degrees -+ {LCD_STEP_CMD_DATA, 0x0004, 0x0000,}, // Scaling Control register (R04h) Page 16, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0008, 0x0207,}, // Display Control 2 (R08h) Page 17, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0009, 0x0000,}, // Display Control 3 (R09h) Page 18, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x000A, 0x0000,}, // Frame Cycle Control (R0Ah) Page 19, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x000C, 0x0000,}, // External Display Interface Control 1 (R0Ch) Page 20, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x000D, 0x0000,}, // Frame Maker Position (R0Dh) Page 21, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x000F, 0x0000,}, // External Display Interface Control 2 (R0Fh) Page 21, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0010, 0x0000,}, // Power Control 1 (R10h) Page 22, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h) Page 23, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0012, 0x0000,}, // Power Control 3 (R12h) Page 24, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0013, 0x0000,}, // Power Control 4 (R13h) Page 25, SPFD5408B Datasheet -+ {LCD_STEP_SLEEP, 0, 200}, -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0101,}, // Display Control (R07h) Page 16, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0010, 0x12B0,}, // Power Control 1 (R10h) Page 22, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h) Page 23, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0012, 0x01BB,}, // Power Control 3 (R12h) Page 24, SPFD5408B Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ {LCD_STEP_CMD_DATA, 0x0013, 0x1300,}, // Power Control 4 (R13h) Page 25, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0029, 0x0010,}, // NVM read data 2 (R29h) Page 30, SPFD5408B Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ {LCD_STEP_CMD_DATA, 0x0030, 0x000A,}, // Gamma Control 1 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0031, 0x1326,}, // Gamma Control 2 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0032, 0x0A29,}, // Gamma Control 3 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0033, 0x290A,}, // Gamma Control 4 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0034, 0x2613,}, // Gamma Control 5 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0035, 0x0A0A,}, // Gamma Control 6 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0036, 0x1E03,}, // Gamma Control 7 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0037, 0x031E,}, // Gamma Control 8 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0038, 0x0706,}, // Gamma Control 9 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0039, 0x0303,}, // Gamma Control 10 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003A, 0x0E04,}, // Gamma Control 11 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003B, 0x0E01,}, // Gamma Control 12 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003C, 0x010E,}, // Gamma Control 13 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003D, 0x040E,}, // Gamma Control 14 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003E, 0x0303,}, // Gamma Control 15 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x003F, 0x0607,}, // Gamma Control 16 Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0050, 0x0000,}, // Window Horizontal RAM Address Start (R50h) Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0051, 0x00EF,}, // Window Horizontal RAM Address End (R51h) Page 32, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0052, 0x0000,}, // Window Vertical RAM Address Start (R52h) Page 33, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0053, 0x013F,}, // Window Vertical RAM Address End (R53h) Page 33, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0060, 0x2700,}, // Driver Output Control (R60h) Page 33, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0061, 0x0001,}, // Driver Output Control (R61h) Page 35, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x006A, 0x0000,}, // Vertical Scroll Control (R6Ah) Page 35, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0080, 0x0000,}, // Display Position - Partial Display 1 (R80h) Page 35, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0081, 0x0000,}, // RAM Address Start - Partial Display 1 (R81h) Page 35, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0082, 0x0000,}, // RAM Address End - Partial Display 1 (R82h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0083, 0x0000,}, // Display Position - Partial Display 2 (R83h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0084, 0x0000,}, // RAM Address Start - Partial Display 2 (R84h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0085, 0x0000,}, // RAM Address End - Partial Display 2 (R85h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0090, 0x0010,}, // Panel Interface Control 1 (R90h) Page 36, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0092, 0x0000,}, // Panel Interface Control 2 (R92h) Page 37, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0093, 0x0103,}, // Panel Interface control 3 (R93h) Page 38, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0095, 0x0210,}, // Panel Interface control 4 (R95h) Page 38, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0097, 0x0000,}, // Panel Interface Control 5 (R97h) Page 40, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0098, 0x0000,}, // Panel Interface Control 6 (R98h) Page 41, SPFD5408B Datasheet -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0173,}, // Display Control (R07h) Page 16, SPFD5408B Datasheet -+ {LCD_STEP_DONE, 0, 0}, -+}; -+ -+const struct ubicom32lcd_panel cfaf240320ktts_180 = { -+ .desc = "CFAF240320KTTS 180", -+ .init_seq = cfaf240320ktts_init_180, -+ .horz_reg = 0x20, -+ .vert_reg = 0x21, -+ .gram_reg = 0x22, -+ .xres = 240, -+ .yres = 320, -+ .stride = 240, -+ .id = 0x5408, -+}; -+#endif -+ -+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_P -+static const struct ubicom32lcd_step tft2n0369ep_init[] = { -+ {LCD_STEP_CMD_DATA, 0x0028, 0x0006}, -+ {LCD_STEP_CMD_DATA, 0x0000, 0x0001}, -+ {LCD_STEP_SLEEP, 0, 15}, -+ {LCD_STEP_CMD_DATA, 0x002B, 0x9532}, -+ {LCD_STEP_CMD_DATA, 0x0003, 0xAAAC}, -+ {LCD_STEP_CMD_DATA, 0x000C, 0x0002}, -+ {LCD_STEP_CMD_DATA, 0x000D, 0x000A}, -+ {LCD_STEP_CMD_DATA, 0x000E, 0x2C00}, -+ {LCD_STEP_CMD_DATA, 0x001E, 0x00AA}, -+ {LCD_STEP_CMD_DATA, 0x0025, 0x8000}, -+ {LCD_STEP_SLEEP, 0, 15}, -+ {LCD_STEP_CMD_DATA, 0x0001, 0x2B3F}, -+ {LCD_STEP_CMD_DATA, 0x0002, 0x0600}, -+ {LCD_STEP_CMD_DATA, 0x0010, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0011, 0x6030}, -+ {LCD_STEP_SLEEP, 0, 20}, -+ {LCD_STEP_CMD_DATA, 0x0005, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0006, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0016, 0xEF1C}, -+ {LCD_STEP_CMD_DATA, 0x0017, 0x0003}, -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0233}, -+ {LCD_STEP_CMD_DATA, 0x000B, 0x5312}, -+ {LCD_STEP_CMD_DATA, 0x000F, 0x0000}, -+ {LCD_STEP_SLEEP, 0, 20}, -+ {LCD_STEP_CMD_DATA, 0x0041, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0042, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0048, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0049, 0x013F}, -+ {LCD_STEP_CMD_DATA, 0x0044, 0xEF00}, -+ {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0046, 0x013F}, -+ {LCD_STEP_CMD_DATA, 0x004A, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x004B, 0x0000}, -+ {LCD_STEP_SLEEP, 0, 20}, -+ {LCD_STEP_CMD_DATA, 0x0030, 0x0707}, -+ {LCD_STEP_CMD_DATA, 0x0031, 0x0704}, -+ {LCD_STEP_CMD_DATA, 0x0032, 0x0204}, -+ {LCD_STEP_CMD_DATA, 0x0033, 0x0201}, -+ {LCD_STEP_CMD_DATA, 0x0034, 0x0203}, -+ {LCD_STEP_CMD_DATA, 0x0035, 0x0204}, -+ {LCD_STEP_CMD_DATA, 0x0036, 0x0204}, -+ {LCD_STEP_CMD_DATA, 0x0037, 0x0502}, -+ {LCD_STEP_CMD_DATA, 0x003A, 0x0302}, -+ {LCD_STEP_CMD_DATA, 0x003B, 0x0500}, -+ {LCD_STEP_SLEEP, 0, 20}, -+ {LCD_STEP_CMD_DATA, 0x0044, 239 << 8 | 0}, -+ {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0046, 319}, -+ {LCD_STEP_DONE, 0, 0}, -+}; -+ -+const struct ubicom32lcd_panel tft2n0369ep = { -+ .desc = "TFT2N0369E-Portrait", -+ .init_seq = tft2n0369ep_init, -+ .horz_reg = 0x4e, -+ .vert_reg = 0x4f, -+ .gram_reg = 0x22, -+ .xres = 240, -+ .yres = 320, -+ .stride = 240, -+ .id = 0x8989, -+}; -+#endif -+ -+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_L -+static const struct ubicom32lcd_step tft2n0369e_init[] = { -+ {LCD_STEP_CMD_DATA, 0x0028, 0x0006}, -+ {LCD_STEP_CMD_DATA, 0x0000, 0x0001}, -+ {LCD_STEP_SLEEP, 0, 15}, -+ {LCD_STEP_CMD_DATA, 0x002B, 0x9532}, -+ {LCD_STEP_CMD_DATA, 0x0003, 0xAAAC}, -+ {LCD_STEP_CMD_DATA, 0x000C, 0x0002}, -+ {LCD_STEP_CMD_DATA, 0x000D, 0x000A}, -+ {LCD_STEP_CMD_DATA, 0x000E, 0x2C00}, -+ {LCD_STEP_CMD_DATA, 0x001E, 0x00AA}, -+ {LCD_STEP_CMD_DATA, 0x0025, 0x8000}, -+ {LCD_STEP_SLEEP, 0, 15}, -+ {LCD_STEP_CMD_DATA, 0x0001, 0x2B3F}, -+ {LCD_STEP_CMD_DATA, 0x0002, 0x0600}, -+ {LCD_STEP_CMD_DATA, 0x0010, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0011, 0x60A8}, -+ {LCD_STEP_SLEEP, 0, 20}, -+ {LCD_STEP_CMD_DATA, 0x0005, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0006, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0016, 0xEF1C}, -+ {LCD_STEP_CMD_DATA, 0x0017, 0x0003}, -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0233}, -+ {LCD_STEP_CMD_DATA, 0x000B, 0x5312}, -+ {LCD_STEP_CMD_DATA, 0x000F, 0x0000}, -+ {LCD_STEP_SLEEP, 0, 20}, -+ {LCD_STEP_CMD_DATA, 0x0041, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0042, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0048, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0049, 0x013F}, -+ {LCD_STEP_CMD_DATA, 0x0044, 0xEF00}, -+ {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0046, 0x013F}, -+ {LCD_STEP_CMD_DATA, 0x004A, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x004B, 0x0000}, -+ {LCD_STEP_SLEEP, 0, 20}, -+ {LCD_STEP_CMD_DATA, 0x0030, 0x0707}, -+ {LCD_STEP_CMD_DATA, 0x0031, 0x0704}, -+ {LCD_STEP_CMD_DATA, 0x0032, 0x0204}, -+ {LCD_STEP_CMD_DATA, 0x0033, 0x0201}, -+ {LCD_STEP_CMD_DATA, 0x0034, 0x0203}, -+ {LCD_STEP_CMD_DATA, 0x0035, 0x0204}, -+ {LCD_STEP_CMD_DATA, 0x0036, 0x0204}, -+ {LCD_STEP_CMD_DATA, 0x0037, 0x0502}, -+ {LCD_STEP_CMD_DATA, 0x003A, 0x0302}, -+ {LCD_STEP_CMD_DATA, 0x003B, 0x0500}, -+ {LCD_STEP_SLEEP, 0, 20}, -+ {LCD_STEP_CMD_DATA, 0x0044, 239 << 8 | 0}, -+ {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0046, 319}, -+ {LCD_STEP_DONE, 0, 0}, -+}; -+ -+const struct ubicom32lcd_panel tft2n0369e = { -+ .desc = "TFT2N0369E-Landscape", -+ .init_seq = tft2n0369e_init, -+ .horz_reg = 0x4e, -+ .vert_reg = 0x4f, -+ .gram_reg = 0x22, -+ .xres = 320, -+ .yres = 240, -+ .stride = 320, -+ .id = 0x8989, -+}; -+#endif -+ -+#ifdef CONFIG_LCD_UBICOM32_CFAF240400D -+static const struct ubicom32lcd_step cfaf240400d_init[] = { -+ {LCD_STEP_CMD_DATA, 0x0606, 0x0000}, // Pin Control (R606h) // Page 41 of SPFD5420A Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0001}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ {LCD_STEP_CMD_DATA, 0x0110, 0x0001}, // Power Control 6(R110h) // Page 30 of SPFD5420A Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ {LCD_STEP_CMD_DATA, 0x0100, 0x17B0}, // Power Control 1 (R100h) // Page 26 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0101, 0x0147}, // Power Control 2 (R101h) // Page 27 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0102, 0x019D}, // Power Control 3 (R102h) // Page 28 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0103, 0x3600}, // Power Control 4 (R103h) // Page 29 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0281, 0x0010}, // NVM read data 2 (R281h) // Page 34 of SPFD5420A Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ {LCD_STEP_CMD_DATA, 0x0102, 0x01BD}, // Power Control 3 (R102h) // Page 28 of SPFD5420A Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ -+ //--------------- Power control 1~6 ---------------// -+ {LCD_STEP_CMD_DATA, 0x0100, 0x16B0}, // Power Control 1 (R100h) // Page 26 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0101, 0x0147}, // Power Control 2 (R101h) // Page 27 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0102, 0x01BD}, // Power Control 3 (R102h) // Page 28 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0103, 0x2d00}, // Power Control 4 (R103h) // Page 29 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0107, 0x0000}, // Power Control 5 (R107h) // Page 30 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0110, 0x0001}, // Power Control 6(R110h) // Page 30 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0280, 0x0000}, // NVM read data 1 (R280h) // Page 33 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0281, 0x0006}, // NVM read data 2 (R281h) // Page 34 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0282, 0x0000}, // NVM read data 3 (R282h) // Page 34 of SPFD5420A Datasheet -+ -+ //------- Gamma 2.2 control (R300h to R30Fh) ------// -+ {LCD_STEP_CMD_DATA, 0x0300, 0x0101}, -+ {LCD_STEP_CMD_DATA, 0x0301, 0x0b27}, -+ {LCD_STEP_CMD_DATA, 0x0302, 0x132a}, -+ {LCD_STEP_CMD_DATA, 0x0303, 0x2a13}, -+ {LCD_STEP_CMD_DATA, 0x0304, 0x270b}, -+ {LCD_STEP_CMD_DATA, 0x0305, 0x0101}, -+ {LCD_STEP_CMD_DATA, 0x0306, 0x1205}, -+ {LCD_STEP_CMD_DATA, 0x0307, 0x0512}, -+ {LCD_STEP_CMD_DATA, 0x0308, 0x0005}, -+ {LCD_STEP_CMD_DATA, 0x0309, 0x0003}, -+ {LCD_STEP_CMD_DATA, 0x030A, 0x0f04}, -+ {LCD_STEP_CMD_DATA, 0x030B, 0x0f00}, -+ {LCD_STEP_CMD_DATA, 0x030C, 0x000f}, -+ {LCD_STEP_CMD_DATA, 0x030D, 0x040f}, -+ {LCD_STEP_CMD_DATA, 0x030E, 0x0300}, -+ {LCD_STEP_CMD_DATA, 0x030F, 0x0500}, -+ -+ {LCD_STEP_CMD_DATA, 0x0400, 0x3500}, // Base Image Number of Line (R400h) // Page 36 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0401, 0x0001}, // Base Image Display Control (R401h) // Page 39 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0404, 0x0000}, // Based Image Vertical Scroll Control (R404h) // Page 40 of SPFD5420A Datasheet -+ -+ //--------------- Normal set ---------------// -+ {LCD_STEP_CMD_DATA, 0x0000, 0x0000}, // ID Read Register (R000h) // Page 13 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0001, 0x0100}, // Driver Output Control Register (R001h) // Page 14 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0002, 0x0100}, // LCD Driving Waveform Control (R002h) // Page 14 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0003, 0x1030}, // Entry Mode (R003h) // Page 15 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0006, 0x0000}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0008, 0x0808}, // Display Control 2 (R008h) // Page 17 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0009, 0x0001}, // Display Control 3 (R009h) // Page 18 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x000B, 0x0010}, // Low Power Control (R00Bh) // Page 19 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x000C, 0x0000}, // External Display Interface Control 1 (R00Ch) // Page 19 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x000F, 0x0000}, // External Display Interface Control 2 (R00Fh) // Page 20 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0001}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet -+ -+ //--------------- Panel interface control 1~6 ---------------// -+ {LCD_STEP_CMD_DATA, 0x0010, 0x0012}, // Panel Interface Control 1 (R010h) // Page 20 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0011, 0x0202}, // Panel Interface Control 2 (R011h) // Page 21 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0012, 0x0300}, // Panel Interface control 3 (R012h) // Page 22 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0020, 0x021E}, // Panel Interface control 4 (R020h) // Page 22 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0021, 0x0202}, // Panel Interface Control 5 (021Rh) // Page 24 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0022, 0x0100}, // Panel Interface Control 6 (R022h) // Page 25 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0090, 0x8000}, // Frame Marker Control (R090h) // Page 25 of SPFD5420A Datasheet -+ -+ //--------------- Partial display ---------------// -+ {LCD_STEP_CMD_DATA, 0x0210, 0x0000}, // Window Horizontal RAM Address Start (R210h) // Page 35 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0211, 0x00EF}, // Window Horziontal RAM Address End (R211h) // Page 35 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0212, 0x0000}, // Window Vertical RAM Address Start (R212h) // Page 35 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0213, 0x018F}, // Window Vertical RAM Address End (R213h) // Page 35 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0500, 0x0000}, // Display Position - Partial Display 1 (R500h) // Page 40 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0501, 0x0000}, // RAM Address Start - Partial Display 1 (R501h)// Page 40 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0502, 0x0000}, // RAM Address End - Partail Display 1 (R502h) // Page 40 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0503, 0x0000}, // Display Position - Partial Display 2 (R503h) // Page 40 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0504, 0x0000}, // RAM Address Start . Partial Display 2 (R504h)// Page 41 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0505, 0x0000}, // RAM Address End . Partial Display 2 (R505h) // Page 41 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0606, 0x0000}, // Pin Control (R606h) // Page 41 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x06F0, 0x0000}, // NVM Access Control (R6F0h) // Page 41 of SPFD5420A Datasheet -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0173}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet -+ {LCD_STEP_SLEEP, 0, 50}, -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0171}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet -+ {LCD_STEP_SLEEP, 0, 10}, -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0173}, // Display Control 1 (R007h) // Page 16 of SPFD5420A Datasheet -+ {LCD_STEP_DONE, 0, 0}, -+}; -+ -+const struct ubicom32lcd_panel cfaf240400d = { -+ .desc = "CFAF240400D", -+ .init_seq = cfaf240400d_init, -+ .horz_reg = 0x0200, -+ .vert_reg = 0x0201, -+ .gram_reg = 0x0202, -+ .xres = 240, -+ .yres = 400, -+ .stride = 240, -+ .id = 0x5420, -+}; -+#endif -+ -+#ifdef CONFIG_LCD_UBICOM32_CFAF240400F -+static const struct ubicom32lcd_step cfaf320240f_init[] = { -+ {LCD_STEP_CMD_DATA, 0x0028, 0x0006}, // VCOM OTP Page 55-56 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0000, 0x0001}, // start Oscillator Page 36 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0010, 0x0000}, // Sleep mode Page 49 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0001, 0x32EF}, // Driver Output Control Page 36-39 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0002, 0x0600}, // LCD Driving Waveform Control Page 40-42 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0003, 0x6A38}, // Power Control 1 Page 43-44 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0011, 0x6870}, // Entry Mode Page 50-52 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0X000F, 0x0000}, // Gate Scan Position Page 49 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0X000B, 0x5308}, // Frame Cycle Control Page 45 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x000C, 0x0003}, // Power Control 2 Page 47 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x000D, 0x000A}, // Power Control 3 Page 48 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x000E, 0x2E00}, // Power Control 4 Page 48 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x001E, 0x00BE}, // Power Control 5 Page 53 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0025, 0x8000}, // Frame Frequency Control Page 53 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0026, 0x7800}, // Analog setting Page 54 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x004E, 0x0000}, // Ram Address Set Page 58 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x004F, 0x0000}, // Ram Address Set Page 58 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0012, 0x08D9}, // Sleep mode Page 49 of SSD2119 datasheet -+ -+ // Gamma Control (R30h to R3Bh) -- Page 56 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0030, 0x0000}, -+ {LCD_STEP_CMD_DATA, 0x0031, 0x0104}, -+ {LCD_STEP_CMD_DATA, 0x0032, 0x0100}, -+ {LCD_STEP_CMD_DATA, 0x0033, 0x0305}, -+ {LCD_STEP_CMD_DATA, 0x0034, 0x0505}, -+ {LCD_STEP_CMD_DATA, 0x0035, 0x0305}, -+ {LCD_STEP_CMD_DATA, 0x0036, 0x0707}, -+ {LCD_STEP_CMD_DATA, 0x0037, 0x0300}, -+ {LCD_STEP_CMD_DATA, 0x003A, 0x1200}, -+ {LCD_STEP_CMD_DATA, 0x003B, 0x0800}, -+ -+ {LCD_STEP_CMD_DATA, 0x0007, 0x0033}, // Display Control Page 45 of SSD2119 datasheet -+ -+ {LCD_STEP_CMD_DATA, 0x0044, 0xEF00}, // Vertical RAM address position Page 57 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0045, 0x0000}, // Horizontal RAM address position Page 57 of SSD2119 datasheet -+ {LCD_STEP_CMD_DATA, 0x0046, 0x013F}, // Horizontal RAM address position Page 57 of SSD2119 datasheet -+ -+ {LCD_STEP_SLEEP, 0, 150}, -+ -+ {LCD_STEP_DONE, 0, 0}, -+}; -+ -+const struct ubicom32lcd_panel cfaf320240f = { -+ .desc = "CFAF320240F", -+ .init_seq = cfaf320240f_init, -+ .horz_reg = 0x4e, -+ .vert_reg = 0x4f, -+ .gram_reg = 0x22, -+ .xres = 320, -+ .yres = 240, -+ .stride = 320, -+ .id = 0x9919, -+}; -+#endif -+ -+const struct ubicom32lcd_panel *ubicom32lcd_panels[] = { -+#ifdef CONFIG_LCD_UBICOM32_CFAF240400KTTS_180 -+ &cfaf240320ktts_180, -+#endif -+#ifdef CONFIG_LCD_UBICOM32_CFAF240400KTTS -+ &cfaf240320ktts_0, -+#endif -+#ifdef CONFIG_LCD_UBICOM32_CFAF240400D -+ &cfaf240400d, -+#endif -+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_P -+ &tft2n0369ep, -+#endif -+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_L -+ &tft2n0369e, -+#endif -+#ifdef CONFIG_LCD_UBICOM32_CFAF240400F -+ &cfaf320240f, -+#endif -+ NULL, -+}; -+ -+#endif -diff -ruN linux-2.6.30.10/drivers/video/backlight/ubicom32lcdpower.c linux-2.6.30.10-ubi/drivers/video/backlight/ubicom32lcdpower.c ---- linux-2.6.30.10/drivers/video/backlight/ubicom32lcdpower.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/backlight/ubicom32lcdpower.c 2009-12-11 11:45:20.000000000 +0200 -@@ -0,0 +1,194 @@ -+/* -+ * drivers/video/backlight/ubicom32lcdpowerpower.c -+ * LCD power driver for the Ubicom32 platform -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define DRIVER_NAME "ubicom32lcdpower" -+ -+struct ubicom32lcdpower_data { -+ /* -+ * Pointer to the platform data structure. Keep this around since we need values -+ * from it to set the backlight intensity. -+ */ -+ const struct ubicom32lcdpower_platform_data *pdata; -+ -+ /* -+ * LCD device, we have to save this for use when we remove ourselves. -+ */ -+ struct lcd_device *lcddev; -+}; -+ -+/* -+ * ubicom32lcdpower_set_power -+ */ -+static int ubicom32lcdpower_set_power(struct lcd_device *ld, int power) -+{ -+ struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld); -+ if (power == FB_BLANK_UNBLANK) { -+ gpio_direction_output(ud->pdata->vgh_gpio, ud->pdata->vgh_polarity); -+ return 0; -+ } -+ -+ gpio_direction_output(ud->pdata->vgh_gpio, !ud->pdata->vgh_polarity); -+ return 0; -+} -+ -+/* -+ * ubicom32lcdpower_get_power -+ */ -+static int ubicom32lcdpower_get_power(struct lcd_device *ld) -+{ -+ struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld); -+ int vgh = gpio_get_value(ud->pdata->vgh_gpio); -+ if ((vgh && ud->pdata->vgh_polarity) || (!vgh && !ud->pdata->vgh_polarity)) { -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static struct lcd_ops ubicom32lcdpower_ops = { -+ .get_power = ubicom32lcdpower_get_power, -+ .set_power = ubicom32lcdpower_set_power, -+}; -+ -+/* -+ * ubicom32lcdpower_probe -+ */ -+static int ubicom32lcdpower_probe(struct platform_device *pdev) -+{ -+ const struct ubicom32lcdpower_platform_data *pdata = pdev->dev.platform_data; -+ struct ubicom32lcdpower_data *ud; -+ struct lcd_device *lcddev; -+ int retval; -+ -+ /* -+ * Check to see if we have any platform data, if we don't have a LCD to control -+ */ -+ if (!pdata) { -+ return -ENODEV; -+ } -+ -+ /* -+ * Allocate our private data -+ */ -+ ud = kzalloc(sizeof(struct ubicom32lcdpower_data), GFP_KERNEL); -+ if (!ud) { -+ return -ENOMEM; -+ } -+ -+ ud->pdata = pdata; -+ -+ /* -+ * Request our GPIOs -+ */ -+ retval = gpio_request(pdata->vgh_gpio, "vgh"); -+ if (retval) { -+ dev_err(&pdev->dev, "Failed to allocate vgh GPIO\n"); -+ goto fail_gpio; -+ } -+ -+ /* -+ * Register our lcd device -+ */ -+ lcddev = lcd_device_register(DRIVER_NAME, &pdev->dev, ud, &ubicom32lcdpower_ops); -+ if (IS_ERR(lcddev)) { -+ retval = PTR_ERR(lcddev); -+ goto fail; -+ } -+ -+ ud->lcddev = lcddev; -+ platform_set_drvdata(pdev, ud); -+ -+ ubicom32lcdpower_set_power(lcddev, FB_BLANK_UNBLANK); -+ -+ printk(KERN_INFO DRIVER_NAME ": LCD driver started\n"); -+ -+ return 0; -+ -+fail: -+ gpio_free(pdata->vgh_gpio); -+ -+fail_gpio: -+ platform_set_drvdata(pdev, NULL); -+ kfree(ud); -+ return retval; -+} -+ -+/* -+ * ubicom32lcdpower_remove -+ */ -+static int __exit ubicom32lcdpower_remove(struct platform_device *pdev) -+{ -+ struct ubicom32lcdpower_data *ud = platform_get_drvdata(pdev); -+ -+ lcd_device_unregister(ud->lcddev); -+ platform_set_drvdata(pdev, NULL); -+ kfree(ud); -+ -+ return 0; -+} -+ -+static struct platform_driver ubicom32lcdpower_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ -+ .remove = __exit_p(ubicom32lcdpower_remove), -+}; -+ -+/* -+ * ubicom32lcdpower_init -+ */ -+static int __init ubicom32lcdpower_init(void) -+{ -+ return platform_driver_probe(&ubicom32lcdpower_driver, ubicom32lcdpower_probe); -+} -+module_init(ubicom32lcdpower_init); -+ -+/* -+ * ubicom32lcdpower_exit -+ */ -+static void __exit ubicom32lcdpower_exit(void) -+{ -+ platform_driver_unregister(&ubicom32lcdpower_driver); -+} -+module_exit(ubicom32lcdpower_exit); -+ -+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); -+MODULE_DESCRIPTION("Ubicom32 lcd power driver"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/drivers/video/Kconfig linux-2.6.30.10-ubi/drivers/video/Kconfig ---- linux-2.6.30.10/drivers/video/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/Kconfig 2009-12-11 11:45:20.000000000 +0200 -@@ -609,6 +609,50 @@ +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -609,6 +609,50 @@ config FB_BFIN_T350MCQB This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. @@ -53202,10 +1266,9 @@ diff -ruN linux-2.6.30.10/drivers/video/Kconfig linux-2.6.30.10-ubi/drivers/vide config FB_STI tristate "HP STI frame buffer device support" -diff -ruN linux-2.6.30.10/drivers/video/Makefile linux-2.6.30.10-ubi/drivers/video/Makefile ---- linux-2.6.30.10/drivers/video/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/Makefile 2009-12-11 11:45:20.000000000 +0200 -@@ -136,6 +136,10 @@ +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -136,6 +136,10 @@ obj-$(CONFIG_FB_BF54X_LQ043) += bf54x- obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o @@ -53216,2184 +1279,9 @@ diff -ruN linux-2.6.30.10/drivers/video/Makefile linux-2.6.30.10-ubi/drivers/vid # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o -diff -ruN linux-2.6.30.10/drivers/video/ubicom32fb.c linux-2.6.30.10-ubi/drivers/video/ubicom32fb.c ---- linux-2.6.30.10/drivers/video/ubicom32fb.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/ubicom32fb.c 2009-12-11 11:45:21.000000000 +0200 -@@ -0,0 +1,779 @@ -+/* -+ * drivers/video/ubicom32fb.c -+ * Ubicom32 frame buffer driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+/* -+ * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by -+ * Geert Uytterhoeven. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#define DRIVER_NAME "ubicom32fb" -+#define DRIVER_DESCRIPTION "Ubicom32 frame buffer driver" -+ -+#define PALETTE_ENTRIES_NO 16 -+ -+/* -+ * Option variables -+ * -+ * vram_size: VRAM size in kilobytes, subject to alignment -+ */ -+static int vram_size = 0; -+module_param(vram_size, int, 0); -+MODULE_PARM_DESC(vram, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment"); -+static int init_value = 0; -+module_param(init_value, int, 0); -+MODULE_PARM_DESC(init, "Initial value of the framebuffer (16-bit number)."); -+ -+/* -+ * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in. -+ */ -+static struct fb_fix_screeninfo ubicom32fb_fix = { -+ .id = "Ubicom32", -+ .type = FB_TYPE_PACKED_PIXELS, -+ .visual = FB_VISUAL_TRUECOLOR, -+ .accel = FB_ACCEL_UBICOM32, -+}; -+ -+/* -+ * Filled in at probe time when we find out what the hardware supports -+ */ -+static struct fb_var_screeninfo ubicom32fb_var; -+ -+/* -+ * Private data structure -+ */ -+struct ubicom32fb_drvdata { -+ struct fb_info *fbinfo; -+ bool cmap_alloc; -+ -+ /* -+ * The address of the framebuffer in memory -+ */ -+ void *fb; -+ void *fb_aligned; -+ -+ /* -+ * Total size of vram including alignment allowance -+ */ -+ u32 total_vram_size; -+ -+ /* -+ * Interrupt to set when changing registers -+ */ -+ u32 vp_int; -+ -+ /* -+ * Optional: Interrupt used by TIO to signal us -+ */ -+ u32 rx_int; -+ -+ /* -+ * Base address of the regs for VDC_TIO -+ */ -+ volatile struct vdc_tio_vp_regs *regs; -+ -+ /* -+ * non-zero if we are in yuv mode -+ */ -+ u8_t is_yuv; -+ -+ /* -+ * Fake palette of 16 colors -+ */ -+ u32 pseudo_palette[PALETTE_ENTRIES_NO]; -+ -+ /* -+ * Wait queue and lock used to block when we need to wait -+ * for something to happen. -+ */ -+ wait_queue_head_t waitq; -+ struct mutex lock; -+ -+}; -+ -+/* -+ * ubicom32fb_set_next_frame -+ * Sets the next frame buffer to display -+ * -+ * if sync is TRUE then this function will block until the hardware -+ * acknowledges the change -+ */ -+static inline void ubicom32fb_set_next_frame(struct ubicom32fb_drvdata *ud, void *fb, u8_t sync) -+{ -+ ud->regs->next_frame_flags = ud->is_yuv ? VDCTIO_NEXT_FRAME_FLAG_YUV : 0; -+ ud->regs->next_frame = (void *)((u32_t)fb | 1); -+ -+ /* -+ * If we have interrupts, then we can wait on it -+ */ -+ if (ud->rx_int != -1) { -+ DEFINE_WAIT(wait); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ud->lock, flags); -+ prepare_to_wait(&ud->waitq, &wait, TASK_INTERRUPTIBLE); -+ spin_unlock_irqrestore(&ud->lock, flags); -+ schedule(); -+ finish_wait(&ud->waitq, &wait); -+ return; -+ } -+ -+ /* -+ * No interrupt, we will just spin here -+ */ -+ while (sync && ((u32_t)ud->regs->next_frame & 1)); -+} -+ -+/* -+ * ubicom32fb_send_command -+ * Sends a command/data pair to the VDC -+ */ -+static inline void ubicom32fb_send_command(struct ubicom32fb_drvdata *ud, u16 command, u8_t block) -+{ -+ ud->regs->command = command; -+ ubicom32_set_interrupt(ud->vp_int); -+ while (block && ud->regs->command); -+} -+ -+/* -+ * ubicom32fb_ioctl -+ * Handles any ioctls sent to us -+ */ -+static int ubicom32fb_ioctl(struct fb_info *fbi, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)fbi->par; -+ void __user *argp = (void __user *)arg; -+ int retval = -EFAULT; -+ -+ switch (cmd) { -+ case UBICOM32FB_IOCTL_SET_NEXT_FRAME_SYNC: -+ // check alignment, return -EINVAL if necessary -+ ubicom32fb_set_next_frame(ud, argp, 1); -+ retval = 0; -+ break; -+ -+ case UBICOM32FB_IOCTL_SET_NEXT_FRAME: -+ // check alignment, return -EINVAL if necessary -+ ubicom32fb_set_next_frame(ud, argp, 0); -+ retval = 0; -+ break; -+ -+ case UBICOM32FB_IOCTL_SET_MODE: -+ if (!(ud->regs->caps & VDCTIO_CAPS_SUPPORTS_SCALING)) { -+ break; -+ } else { -+ struct ubicom32fb_mode mode; -+ volatile struct vdc_tio_vp_regs *regs = ud->regs; -+ u32_t flags = 0; -+ -+ if (copy_from_user(&mode, argp, sizeof(mode))) { -+ break; -+ } -+ -+ regs->x_in = mode.width; -+ regs->y_in = mode.height; -+ regs->x_out = regs->xres; -+ regs->y_out = regs->yres; -+ if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_SCAN_ORDER) { -+ flags |= VDCTIO_SCALE_FLAG_YUV_SCAN_ORDER; -+ } -+ if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_BLOCK_ORDER) { -+ flags |= VDCTIO_SCALE_FLAG_YUV_BLOCK_ORDER; -+ } -+ ud->is_yuv = mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV; -+ if (ud->is_yuv) { -+ flags |= VDCTIO_SCALE_FLAG_YUV; -+ } -+ if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_16_255) { -+ flags |= VDCTIO_SCALE_FLAG_VRANGE_16_255; -+ } -+ if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_0_255) { -+ flags |= VDCTIO_SCALE_FLAG_VRANGE_0_255; -+ } -+ if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VSUB) { -+ flags |= VDCTIO_SCALE_FLAG_VSUB; -+ } -+ if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_2_1) { -+ flags |= VDCTIO_SCALE_FLAG_HSUB_2_1; -+ } -+ if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_1_1) { -+ flags |= VDCTIO_SCALE_FLAG_HSUB_1_1; -+ } -+ if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_SCALE_ENABLE) { -+ flags |= VDCTIO_SCALE_FLAG_ENABLE; -+ } -+ if (mode.next_frame) { -+ flags |= VDCTIO_SCALE_FLAG_SET_FRAME_BUFFER; -+ regs->next_frame = mode.next_frame; -+ } -+ -+ regs->scale_flags = flags; -+ ubicom32fb_send_command(ud, VDCTIO_COMMAND_SET_SCALE_MODE, 1); -+ retval = 0; -+ break; -+ } -+ -+ default: -+ retval = -ENOIOCTLCMD; -+ break; -+ } -+ -+ return retval; -+} -+ -+/* -+ * ubicom32fb_interrupt -+ * Called by the OS when the TIO has set the rx_int -+ */ -+static irqreturn_t ubicom32fb_interrupt(int vec, void *appdata) -+{ -+ struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)appdata; -+ -+ spin_lock(&ud->lock); -+ if (waitqueue_active(&ud->waitq)) { -+ wake_up(&ud->waitq); -+ } -+ spin_unlock(&ud->lock); -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * ubicom32fb_pan_display -+ * Pans the display to a given location. Supports only y direction panning. -+ */ -+static int ubicom32fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) -+{ -+ struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)fbi->par; -+ void *new_addr; -+ -+ /* -+ * Get the last y line that would be displayed. Since we don't support YWRAP, -+ * it must be less than our virtual y size. -+ */ -+ u32 lasty = var->yoffset + var->yres; -+ if (lasty > fbi->var.yres_virtual) { -+ /* -+ * We would fall off the end of our frame buffer if we panned here. -+ */ -+ return -EINVAL; -+ } -+ -+ if (var->xoffset) { -+ /* -+ * We don't support panning in the x direction -+ */ -+ return -EINVAL; -+ } -+ -+ /* -+ * Everything looks sane, go ahead and pan -+ * -+ * We have to calculate a new address for the VDC to look at -+ */ -+ new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length); -+ -+ /* -+ * Send down the command. The buffer will switch at the next vertical blank -+ */ -+ ubicom32fb_set_next_frame(ud, (void *)new_addr, 0); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32fb_setcolreg -+ * Sets a color in our virtual palette -+ */ -+static int ubicom32fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi) -+{ -+ u32 *palette = fbi->pseudo_palette; -+ -+ if (regno >= PALETTE_ENTRIES_NO) { -+ return -EINVAL; -+ } -+ -+ /* -+ * We only use 8 bits from each color -+ */ -+ red >>= 8; -+ green >>= 8; -+ blue >>= 8; -+ -+ /* -+ * Convert any grayscale values -+ */ -+ if (fbi->var.grayscale) { -+ u16 gray = red + green + blue; -+ gray += (gray >> 2) + (gray >> 3) - (gray >> 7); -+ gray >>= 2; -+ if (gray > 255) { -+ gray = 255; -+ } -+ red = gray; -+ blue = gray; -+ green = gray; -+ } -+ -+ palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) | -+ (blue << fbi->var.blue.offset); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32fb_mmap -+ */ -+static int ubicom32fb_mmap(struct fb_info *info, struct vm_area_struct *vma) -+{ -+ struct ubicom32fb_drvdata *drvdata = (struct ubicom32fb_drvdata *)info->par; -+ -+ vma->vm_start = (unsigned long)(drvdata->fb_aligned); -+ -+ vma->vm_end = vma->vm_start + info->fix.smem_len; -+ -+ /* For those who don't understand how mmap works, go read -+ * Documentation/nommu-mmap.txt. -+ * For those that do, you will know that the VM_MAYSHARE flag -+ * must be set in the vma->vm_flags structure on noMMU -+ * Other flags can be set, and are documented in -+ * include/linux/mm.h -+ */ -+ -+ vma->vm_flags |= VM_MAYSHARE | VM_SHARED; -+ -+ return 0; -+} -+ -+/* -+ * ubicom32fb_blank -+ */ -+static int ubicom32fb_blank(int blank_mode, struct fb_info *fbi) -+{ -+ return 0; -+#if 0 -+ struct ubicom32fb_drvdata *drvdata = to_ubicom32fb_drvdata(fbi); -+ -+ switch (blank_mode) { -+ case FB_BLANK_UNBLANK: -+ /* turn on panel */ -+ ubicom32fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); -+ break; -+ -+ case FB_BLANK_NORMAL: -+ case FB_BLANK_VSYNC_SUSPEND: -+ case FB_BLANK_HSYNC_SUSPEND: -+ case FB_BLANK_POWERDOWN: -+ /* turn off panel */ -+ ubicom32fb_out_be32(drvdata, REG_CTRL, 0); -+ default: -+ break; -+ -+ } -+ return 0; /* success */ -+#endif -+} -+ -+static struct fb_ops ubicom32fb_ops = -+{ -+ .owner = THIS_MODULE, -+ .fb_pan_display = ubicom32fb_pan_display, -+ .fb_setcolreg = ubicom32fb_setcolreg, -+ .fb_blank = ubicom32fb_blank, -+ .fb_mmap = ubicom32fb_mmap, -+ .fb_ioctl = ubicom32fb_ioctl, -+ .fb_fillrect = cfb_fillrect, -+ .fb_copyarea = cfb_copyarea, -+ .fb_imageblit = cfb_imageblit, -+}; -+ -+/* -+ * ubicom32fb_release -+ */ -+static int ubicom32fb_release(struct device *dev) -+{ -+ struct ubicom32fb_drvdata *ud = dev_get_drvdata(dev); -+ -+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) -+ //ubicom32fb_blank(VESA_POWERDOWN, &drvdata->info); -+#endif -+ -+ unregister_framebuffer(ud->fbinfo); -+ -+ if (ud->cmap_alloc) { -+ fb_dealloc_cmap(&ud->fbinfo->cmap); -+ } -+ -+ if (ud->fb) { -+ kfree(ud->fb); -+ } -+ -+ if (ud->rx_int != -1) { -+ free_irq(ud->rx_int, ud); -+ } -+ -+ /* -+ * Turn off the display -+ */ -+ //ubicom32fb_out_be32(drvdata, REG_CTRL, 0); -+ //iounmap(drvdata->regs); -+ -+ framebuffer_release(ud->fbinfo); -+ dev_set_drvdata(dev, NULL); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32fb_platform_probe -+ */ -+static int __init ubicom32fb_platform_probe(struct platform_device *pdev) -+{ -+ struct ubicom32fb_drvdata *ud; -+ struct resource *irq_resource_rx; -+ struct resource *irq_resource_tx; -+ struct resource *mem_resource; -+ struct fb_info *fbinfo; -+ int rc; -+ size_t fbsize; -+ struct device *dev = &pdev->dev; -+ int offset; -+ struct vdc_tio_vp_regs *regs; -+ -+ /* -+ * Get our resources -+ */ -+ irq_resource_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -+ if (!irq_resource_tx) { -+ dev_err(dev, "No tx IRQ resource assigned\n"); -+ return -ENODEV; -+ } -+ -+ irq_resource_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1); -+ if (!irq_resource_rx) { -+ dev_err(dev, "No rx IRQ resource assigned\n"); -+ return -ENODEV; -+ } -+ -+ mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!mem_resource || !mem_resource->start) { -+ dev_err(dev, "No mem resource assigned\n"); -+ return -ENODEV; -+ } -+ regs = (struct vdc_tio_vp_regs *)mem_resource->start; -+ if (regs->version != VDCTIO_VP_VERSION) { -+ dev_err(dev, "VDCTIO is not compatible with this driver tio:%x drv:%x\n", -+ regs->version, VDCTIO_VP_VERSION); -+ return -ENODEV; -+ } -+ -+ /* -+ * This is the minimum VRAM size -+ */ -+ fbsize = regs->xres * regs->yres * (regs->bpp / 8); -+ if (!vram_size) { -+ vram_size = (fbsize + 1023) / 1024; -+ } else { -+ if (fbsize > (vram_size * 1024)) { -+ dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize); -+ return -ENOMEM; // should be ebadparam? -+ } -+ } -+ -+ /* -+ * Allocate the framebuffer instance + our private data -+ */ -+ fbinfo = framebuffer_alloc(sizeof(struct ubicom32fb_drvdata), &pdev->dev); -+ if (!fbinfo) { -+ dev_err(dev, "Not enough memory to allocate instance.\n"); -+ return -ENOMEM; -+ } -+ -+ /* -+ * Fill in our private data. -+ */ -+ ud = (struct ubicom32fb_drvdata *)fbinfo->par; -+ ud->fbinfo = fbinfo; -+ ud->regs = (struct vdc_tio_vp_regs *)(mem_resource->start); -+ dev_set_drvdata(dev, ud); -+ -+ ud->vp_int = irq_resource_tx->start; -+ -+ /* -+ * If we were provided an rx_irq then we need to init the appropriate -+ * queues, locks, and functions. -+ */ -+ ud->rx_int = -1; -+ if (irq_resource_rx->start != DEVTREE_IRQ_NONE) { -+ init_waitqueue_head(&ud->waitq); -+ mutex_init(&ud->lock); -+ if (request_irq(ud->rx_int, ubicom32fb_interrupt, IRQF_SHARED, "ubicom32fb_rx", ud)) { -+ dev_err(dev, "Couldn't request rx IRQ\n"); -+ rc = -ENOMEM; -+ goto fail; -+ } -+ ud->rx_int = irq_resource_rx->start; -+ } -+ -+ /* -+ * Allocate and align the requested amount of VRAM -+ */ -+ ud->total_vram_size = (vram_size * 1024) + regs->fb_align; -+ ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL); -+ if (ud->fb == NULL) { -+ dev_err(dev, "Couldn't allocate VRAM\n"); -+ rc = -ENOMEM; -+ goto fail; -+ } -+ -+ offset = (u32_t)ud->fb & (regs->fb_align - 1); -+ if (!offset) { -+ ud->fb_aligned = ud->fb; -+ } else { -+ offset = regs->fb_align - offset; -+ ud->fb_aligned = ud->fb + offset; -+ } -+ -+ /* -+ * Clear the entire frame buffer -+ */ -+ if (!init_value) { -+ memset(ud->fb_aligned, 0, vram_size * 1024); -+ } else { -+ unsigned short *p = ud->fb_aligned; -+ int i; -+ for (i = 0; i < ((vram_size * 1024) / sizeof(u16_t)); i++) { -+ *p++ = init_value; -+ } -+ } -+ -+ /* -+ * Fill in the fb_var_screeninfo structure -+ */ -+ memset(&ubicom32fb_var, 0, sizeof(ubicom32fb_var)); -+ ubicom32fb_var.bits_per_pixel = regs->bpp; -+ ubicom32fb_var.red.offset = regs->rshift; -+ ubicom32fb_var.green.offset = regs->gshift; -+ ubicom32fb_var.blue.offset = regs->bshift; -+ ubicom32fb_var.red.length = regs->rbits; -+ ubicom32fb_var.green.length = regs->gbits; -+ ubicom32fb_var.blue.length = regs->bbits; -+ ubicom32fb_var.activate = FB_ACTIVATE_NOW; -+ -+#if 0 -+ /* -+ * Turn on the display -+ */ -+ ud->reg_ctrl_default = REG_CTRL_ENABLE; -+ if (regs->rotate_screen) -+ ud->reg_ctrl_default |= REG_CTRL_ROTATE; -+ ubicom32fb_out_be32(ud, REG_CTRL, ud->reg_ctrl_default); -+#endif -+ -+ /* -+ * Fill in the fb_info structure -+ */ -+ ud->fbinfo->device = dev; -+ ud->fbinfo->screen_base = (void *)ud->fb_aligned; -+ ud->fbinfo->fbops = &ubicom32fb_ops; -+ ud->fbinfo->fix = ubicom32fb_fix; -+ ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned; -+ ud->fbinfo->fix.smem_len = vram_size * 1024; -+ ud->fbinfo->fix.line_length = regs->xres * (regs->bpp / 8); -+ ud->fbinfo->fix.mmio_start = (u32)regs; -+ ud->fbinfo->fix.mmio_len = sizeof(struct vdc_tio_vp_regs); -+ -+ /* -+ * We support panning in the y direction only -+ */ -+ ud->fbinfo->fix.xpanstep = 0; -+ ud->fbinfo->fix.ypanstep = 1; -+ -+ ud->fbinfo->pseudo_palette = ud->pseudo_palette; -+ ud->fbinfo->flags = FBINFO_DEFAULT; -+ ud->fbinfo->var = ubicom32fb_var; -+ ud->fbinfo->var.xres = regs->xres; -+ ud->fbinfo->var.yres = regs->yres; -+ -+ /* -+ * We cannot pan in the X direction, so xres_virtual is regs->xres -+ * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length -+ */ -+ ud->fbinfo->var.xres_virtual = regs->xres; -+ ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length; -+ -+ //ud->fbinfo->var.height = regs->height_mm; -+ //ud->fbinfo->var.width = regs->width_mm; -+ -+ /* -+ * Allocate a color map -+ */ -+ rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0); -+ if (rc) { -+ dev_err(dev, "Fail to allocate colormap (%d entries)\n", -+ PALETTE_ENTRIES_NO); -+ goto fail; -+ } -+ ud->cmap_alloc = true; -+ -+ /* -+ * Register new frame buffer -+ */ -+ rc = register_framebuffer(ud->fbinfo); -+ if (rc) { -+ dev_err(dev, "Could not register frame buffer\n"); -+ goto fail; -+ } -+ -+ /* -+ * Start up the VDC -+ */ -+ ud->regs->next_frame = ud->fb; -+ ubicom32fb_send_command(ud, VDCTIO_COMMAND_START, 0); -+ -+ /* -+ * Tell the log we are here -+ */ -+ dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u), regs=%p irqtx=%u irqrx=%u\n", -+ ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres, -+ ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual, ud->regs, -+ irq_resource_tx->start, irq_resource_rx->start); -+ -+ /* -+ * Success -+ */ -+ return 0; -+ -+fail: -+ ubicom32fb_release(dev); -+ return rc; -+} -+ -+/* -+ * ubicom32fb_platform_remove -+ */ -+static int ubicom32fb_platform_remove(struct platform_device *pdev) -+{ -+ dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n"); -+ return ubicom32fb_release(&pdev->dev); -+} -+ -+static struct platform_driver ubicom32fb_platform_driver = { -+ .probe = ubicom32fb_platform_probe, -+ .remove = ubicom32fb_platform_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+#ifndef MODULE -+/* -+ * ubicom32fb_setup -+ * Process kernel boot options -+ */ -+static int __init ubicom32fb_setup(char *options) -+{ -+ char *this_opt; -+ -+ if (!options || !*options) { -+ return 0; -+ } -+ -+ while ((this_opt = strsep(&options, ",")) != NULL) { -+ if (!*this_opt) { -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "init_value=", 10)) { -+ init_value = simple_strtoul(this_opt + 11, NULL, 0); -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "vram_size=", 10)) { -+ vram_size = simple_strtoul(this_opt + 10, NULL, 0); -+ continue; -+ } -+ } -+ return 0; -+} -+#endif /* MODULE */ -+ -+/* -+ * ubicom32fb_init -+ */ -+static int __devinit ubicom32fb_init(void) -+{ -+#ifndef MODULE -+ /* -+ * Get kernel boot options (in 'video=ubicom32fb:') -+ */ -+ char *option = NULL; -+ -+ if (fb_get_options(DRIVER_NAME, &option)) { -+ return -ENODEV; -+ } -+ ubicom32fb_setup(option); -+#endif /* MODULE */ -+ -+ return platform_driver_register(&ubicom32fb_platform_driver); -+} -+module_init(ubicom32fb_init); -+ -+/* -+ * ubicom32fb_exit -+ */ -+static void __exit ubicom32fb_exit(void) -+{ -+ platform_driver_unregister(&ubicom32fb_platform_driver); -+} -+module_exit(ubicom32fb_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); -+MODULE_DESCRIPTION(DRIVER_DESCRIPTION); -diff -ruN linux-2.6.30.10/drivers/video/ubicom32plio80.c linux-2.6.30.10-ubi/drivers/video/ubicom32plio80.c ---- linux-2.6.30.10/drivers/video/ubicom32plio80.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/ubicom32plio80.c 2009-12-11 11:45:21.000000000 +0200 -@@ -0,0 +1,780 @@ -+/* -+ * drivers/video/ubicom32plio80.c -+ * Ubicom32 80 bus PLIO buffer driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+/* -+ * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by -+ * Geert Uytterhoeven. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_NAME "ubicom32plio80" -+#define DRIVER_DESCRIPTION "Ubicom32 80 bus PLIO frame buffer driver" -+ -+#define PALETTE_ENTRIES_NO 16 -+ -+/* -+ * Option variables -+ * -+ * vram_size: VRAM size in kilobytes, subject to alignment -+ */ -+static int vram_size = 0; -+module_param(vram_size, int, 0); -+MODULE_PARM_DESC(vram_size, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment"); -+ -+static int xres = 240; -+module_param(xres, int, 0); -+MODULE_PARM_DESC(xres, "x (horizontal) resolution"); -+ -+static int yres = 320; -+module_param(yres, int, 0); -+MODULE_PARM_DESC(yres, "y (vertical) resolution"); -+ -+static int bgr = 0; -+module_param(bgr, int, 0); -+MODULE_PARM_DESC(bgr, "display is BGR (Blue is MSB)"); -+ -+#define BITS_PER_PIXEL 16 -+ -+/* -+ * Buffer alignment, must not be 0 -+ */ -+#define UBICOM32PLIO80_ALIGNMENT 4 -+ -+/* -+ * PLIO FSM -+ * 16-bit data bus on port I -+ * CS on EXTCTL[6] -+ * WR on EXTCTL[4] -+ */ -+static const plio_fctl_t plio_fctl = { -+ .fctl0 = { -+ .ptif_port_mode = PLIO_PORT_MODE_DI, -+ .ptif_portd_cfg = 0, -+ .ptif_porti_cfg = 3, -+ .edif_ds = 6, -+ .edif_cmp_mode = 1, -+ .ecif_extclk_ena = 0, // enable clock output on PD7 table 2.65/p111 says extctl[0]? -+ .icif_clk_src_sel = PLIO_CLK_IO, -+ }, -+ .fctl2 = { -+ .icif_eclk_div = 10, -+ .icif_iclk_div = 10, -+ }, -+ -+ }; -+ -+ static const plio_config_t plio_config = { -+ .pfsm = { -+ /* -+ * Table 12.63 -+ */ -+ .grpsel[0] = {1,1,1,1,1,1,1,1,1,1}, -+ -+ /* -+ * Table 12.66 Counter load value -+ */ -+ .cs_lut[0] = {0,0,0,0,0,0,0,0}, -+ -+ /* -+ * Table 2.75 PLIO PFSM Configuration Registers -+ */ -+ // 3 2 1 0 -+ .extctl_o_lut[0] = {0x3f, 0x2f, 0x3f, 0x3f}, -+ // 7 6 5 4 -+ .extctl_o_lut[1] = {0x3f, 0x3f, 0x3f, 0x2f}, -+ }, -+ .edif = { -+ .odr_oe = 0xffff, -+ }, -+ .ecif = { -+ .output_ena = (1 << 6) | (1 << 4), -+ }, -+}; -+ -+static const u32_t ubicom32plio80_plio_fsm[] = { -+ // 0-F -+ 0x00070007, 0x00070007, -+ 0x00070007, 0x00070007, -+ 0x00070007, 0x00070007, -+ 0x00070007, 0x00070007, -+ -+ 0x16260806, 0x16260806, -+ 0x16260806, 0x16260806, -+ 0x16260806, 0x16260806, -+ 0x16260806, 0x16260806, -+ -+ // 10 - 1f -+ 0x22061806, 0x22061806, -+ 0x22061806, 0x22061806, -+ 0x22061806, 0x22061806, -+ 0x22061806, 0x22061806, -+ -+ 0x22061806, 0x22061806, -+ 0x22061806, 0x22061806, -+ 0x22061806, 0x22061806, -+ 0x22061806, 0x22061806, -+ -+ // 20 - 2f -+ 0x00070806, 0x00070806, -+ 0x00070806, 0x00070806, -+ 0x00070806, 0x00070806, -+ 0x00070806, 0x00070806, -+ -+ 0x00070806, 0x00070806, -+ 0x00070806, 0x00070806, -+ 0x00070806, 0x00070806, -+ 0x00070806, 0x00070806, -+}; -+ -+/* -+ * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in. -+ */ -+static struct fb_fix_screeninfo ubicom32plio80_fix = { -+ .id = "Ubicom32", -+ .type = FB_TYPE_PACKED_PIXELS, -+ .visual = FB_VISUAL_TRUECOLOR, -+ .accel = FB_ACCEL_UBICOM32_PLIO80, -+}; -+ -+/* -+ * Filled in at probe time when we find out what the hardware supports -+ */ -+static struct fb_var_screeninfo ubicom32plio80_var; -+ -+/* -+ * Private data structure -+ */ -+struct ubicom32plio80_drvdata { -+ struct fb_info *fbinfo; -+ bool cmap_alloc; -+ -+ /* -+ * The address of the framebuffer in memory -+ */ -+ void *fb; -+ void *fb_aligned; -+ -+ /* -+ * Total size of vram including alignment allowance -+ */ -+ u32 total_vram_size; -+ -+ /* -+ * Fake palette of 16 colors -+ */ -+ u32 pseudo_palette[PALETTE_ENTRIES_NO]; -+ -+ int irq_req; -+ -+ /* -+ * Current pointer and bytes left to transfer with the PLIO -+ */ -+ void *xfer_ptr; -+ u32 bytes_to_xfer; -+ u32 busy; -+}; -+ -+static struct platform_device *ubicom32plio80_platform_device; -+ -+/* -+ * ubicom32plio80_isr -+ */ -+static int ubicom32plio80_isr(int irq, void *appdata) -+{ -+ struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)appdata; -+ -+ if (!ud->bytes_to_xfer) { -+ ubicom32_disable_interrupt(TX_FIFO_INT(PLIO_PORT)); -+ PLIO_NBR->intmask.txfifo_wm = 0; -+ ud->busy = 0; -+ return IRQ_HANDLED; -+ } -+ -+ asm volatile ( -+ ".rept 8 \n\t" -+ "move.4 (%[fifo]), (%[data])4++ \n\t" -+ ".endr \n\t" -+ : [data] "+a" (ud->xfer_ptr) -+ : [fifo] "a" (&PLIO_NBR->tx_lo) -+ ); -+ -+ ud->bytes_to_xfer -= 32; -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * ubicom32plio80_update -+ */ -+static void ubicom32plio80_update(struct ubicom32plio80_drvdata *ud, u32 *fb) -+{ -+ struct ubicom32_io_port *ri = (struct ubicom32_io_port *)RI; -+ struct ubicom32_io_port *rd = (struct ubicom32_io_port *)RD; -+ -+ ud->xfer_ptr = fb; -+ ud->bytes_to_xfer = (xres * yres * 2) - 64; -+ ud->busy = 1; -+ -+ ri->gpio_mask = 0; -+ rd->gpio_mask &= ~((1 << 4) | (1 << 2)); -+ -+ *(u32 *)(&PLIO_NBR->intclr) = ~0; -+ PLIO_NBR->intmask.txfifo_wm = 1; -+ PLIO_NBR->fifo_wm.tx = 8; -+ ubicom32_enable_interrupt(TX_FIFO_INT(PLIO_PORT)); -+ -+ asm volatile ( -+ ".rept 16 \n\t" -+ "move.4 (%[fifo]), (%[data])4++ \n\t" -+ ".endr \n\t" -+ : [data] "+a" (ud->xfer_ptr) -+ : [fifo] "a" (&PLIO_NBR->tx_lo) -+ ); -+} -+ -+/* -+ * ubicom32plio80_pan_display -+ * Pans the display to a given location. Supports only y direction panning. -+ */ -+static int ubicom32plio80_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) -+{ -+ struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)fbi->par; -+ void *new_addr; -+ -+ /* -+ * Get the last y line that would be displayed. Since we don't support YWRAP, -+ * it must be less than our virtual y size. -+ */ -+ u32 lasty = var->yoffset + var->yres; -+ if (lasty > fbi->var.yres_virtual) { -+ /* -+ * We would fall off the end of our frame buffer if we panned here. -+ */ -+ return -EINVAL; -+ } -+ -+ if (var->xoffset) { -+ /* -+ * We don't support panning in the x direction -+ */ -+ return -EINVAL; -+ } -+ -+ /* -+ * Everything looks sane, go ahead and pan -+ * -+ * We have to calculate a new address for the VDC to look at -+ */ -+ new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32plio80_setcolreg -+ * Sets a color in our virtual palette -+ */ -+static int ubicom32plio80_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi) -+{ -+ u32 *palette = fbi->pseudo_palette; -+ -+ if (regno >= PALETTE_ENTRIES_NO) { -+ return -EINVAL; -+ } -+ -+ /* -+ * We only use 8 bits from each color -+ */ -+ red >>= 8; -+ green >>= 8; -+ blue >>= 8; -+ -+ /* -+ * Convert any grayscale values -+ */ -+ if (fbi->var.grayscale) { -+ u16 gray = red + green + blue; -+ gray += (gray >> 2) + (gray >> 3) - (gray >> 7); -+ gray >>= 2; -+ if (gray > 255) { -+ gray = 255; -+ } -+ red = gray; -+ blue = gray; -+ green = gray; -+ } -+ -+ palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) | -+ (blue << fbi->var.blue.offset); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32plio80_mmap -+ */ -+static int ubicom32plio80_mmap(struct fb_info *info, struct vm_area_struct *vma) -+{ -+ struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)info->par; -+ -+ vma->vm_start = (unsigned long)(ud->fb_aligned); -+ -+ vma->vm_end = vma->vm_start + info->fix.smem_len; -+ -+ /* For those who don't understand how mmap works, go read -+ * Documentation/nommu-mmap.txt. -+ * For those that do, you will know that the VM_MAYSHARE flag -+ * must be set in the vma->vm_flags structure on noMMU -+ * Other flags can be set, and are documented in -+ * include/linux/mm.h -+ */ -+ -+ vma->vm_flags |= VM_MAYSHARE | VM_SHARED; -+ -+ return 0; -+} -+ -+/* -+ * ubicom32plio80_check_var -+ * Check the var, tweak it but don't change operational parameters. -+ */ -+static int ubicom32plio80_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)info->par; -+ u32 line_size = var->xres * (BITS_PER_PIXEL / 8); -+ -+ /* -+ * See if we can handle this bpp -+ */ -+ if (var->bits_per_pixel > BITS_PER_PIXEL) { -+ return -EINVAL; -+ } -+ var->bits_per_pixel = BITS_PER_PIXEL; -+ -+ /* -+ * See if we have enough memory to handle this resolution -+ */ -+ if ((line_size * var->yres * BITS_PER_PIXEL / 8) > ud->total_vram_size) { -+ return -EINVAL; -+ } -+ -+ var->xres_virtual = var->xres; -+ var->yres_virtual = ud->total_vram_size / line_size; -+ -+ var->red.length = 5; -+ var->green.length = 6; -+ var->green.offset = 5; -+ var->blue.length = 5; -+ var->transp.offset = var->transp.length = 0; -+ -+ if (bgr) { -+ var->red.offset = 0; -+ var->blue.offset = 11; -+ } else { -+ var->red.offset = 11; -+ var->blue.offset = 0; -+ } -+ -+ var->nonstd = 0; -+ var->height = -1; -+ var->width = -1; -+ var->vmode = FB_VMODE_NONINTERLACED; -+ var->sync = 0; -+ -+ return 0; -+} -+ -+/* -+ * ubicom32plio80_set_par -+ * Set the video mode according to info->var -+ */ -+static int ubicom32plio80_set_par(struct fb_info *info) -+{ -+ /* -+ * Anything changed? -+ */ -+ if ((xres == info->var.xres) && (yres == info->var.yres)) { -+ return 0; -+ } -+ -+ /* -+ * Implement changes -+ */ -+ xres = info->var.xres; -+ yres = info->var.yres; -+ info->fix.visual = FB_VISUAL_TRUECOLOR; -+ info->fix.xpanstep = 0; -+ info->fix.ypanstep = 1; -+ info->fix.line_length = xres * (BITS_PER_PIXEL / 8); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32plio80_ops -+ * List of supported operations -+ */ -+static struct fb_ops ubicom32plio80_ops = -+{ -+ .owner = THIS_MODULE, -+ .fb_pan_display = ubicom32plio80_pan_display, -+ .fb_setcolreg = ubicom32plio80_setcolreg, -+ .fb_mmap = ubicom32plio80_mmap, -+ .fb_check_var = ubicom32plio80_check_var, -+ .fb_set_par = ubicom32plio80_set_par, -+ .fb_fillrect = cfb_fillrect, -+ .fb_copyarea = cfb_copyarea, -+ .fb_imageblit = cfb_imageblit, -+}; -+ -+/* -+ * ubicom32plio80_release -+ */ -+static int ubicom32plio80_release(struct device *dev) -+{ -+ struct ubicom32plio80_drvdata *ud = dev_get_drvdata(dev); -+ -+ unregister_framebuffer(ud->fbinfo); -+ -+ if (ud->irq_req) { -+ free_irq(TX_FIFO_INT(PLIO_PORT), ud); -+ } -+ if (ud->cmap_alloc) { -+ fb_dealloc_cmap(&ud->fbinfo->cmap); -+ } -+ -+ if (ud->fb) { -+ kfree(ud->fb); -+ } -+ -+ framebuffer_release(ud->fbinfo); -+ dev_set_drvdata(dev, NULL); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32plio80_platform_probe -+ */ -+static int __init ubicom32plio80_platform_probe(struct platform_device *pdev) -+{ -+ struct ubicom32plio80_drvdata *ud; -+ struct fb_info *fbinfo; -+ int rc; -+ size_t fbsize; -+ struct device *dev = &pdev->dev; -+ int offset; -+ -+ /* -+ * This is the minimum VRAM size -+ */ -+ fbsize = xres * yres * 2; -+ if (!vram_size) { -+ vram_size = (fbsize + 1023) / 1024; -+ } else { -+ if (fbsize > (vram_size * 1024)) { -+ dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize); -+ return -ENOMEM; // should be ebadparam? -+ } -+ } -+ -+ /* -+ * Allocate the framebuffer instance + our private data -+ */ -+ fbinfo = framebuffer_alloc(sizeof(struct ubicom32plio80_drvdata), &pdev->dev); -+ if (!fbinfo) { -+ dev_err(dev, "Not enough memory to allocate instance.\n"); -+ return -ENOMEM; -+ } -+ -+ /* -+ * Fill in our private data. -+ */ -+ ud = (struct ubicom32plio80_drvdata *)fbinfo->par; -+ ud->fbinfo = fbinfo; -+ dev_set_drvdata(dev, ud); -+ -+ /* -+ * Allocate and align the requested amount of VRAM -+ */ -+ ud->total_vram_size = (vram_size * 1024) + UBICOM32PLIO80_ALIGNMENT; -+ ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL); -+ if (ud->fb == NULL) { -+ dev_err(dev, "Couldn't allocate VRAM\n"); -+ rc = -ENOMEM; -+ goto fail; -+ } -+ -+ offset = (u32_t)ud->fb & (UBICOM32PLIO80_ALIGNMENT - 1); -+ if (!offset) { -+ ud->fb_aligned = ud->fb; -+ } else { -+ offset = UBICOM32PLIO80_ALIGNMENT - offset; -+ ud->fb_aligned = ud->fb + offset; -+ } -+ -+ /* -+ * Clear the entire frame buffer -+ */ -+ memset(ud->fb_aligned, 0, vram_size * 1024); -+ -+ /* -+ * Fill in the fb_var_screeninfo structure -+ */ -+ memset(&ubicom32plio80_var, 0, sizeof(ubicom32plio80_var)); -+ ubicom32plio80_var.bits_per_pixel = BITS_PER_PIXEL; -+ ubicom32plio80_var.red.length = 5; -+ ubicom32plio80_var.green.length = 6; -+ ubicom32plio80_var.green.offset = 5; -+ ubicom32plio80_var.blue.length = 5; -+ ubicom32plio80_var.activate = FB_ACTIVATE_NOW; -+ -+ if (bgr) { -+ ubicom32plio80_var.red.offset = 0; -+ ubicom32plio80_var.blue.offset = 11; -+ } else { -+ ubicom32plio80_var.red.offset = 11; -+ ubicom32plio80_var.blue.offset = 0; -+ } -+ -+ /* -+ * Fill in the fb_info structure -+ */ -+ ud->fbinfo->device = dev; -+ ud->fbinfo->screen_base = (void *)ud->fb_aligned; -+ ud->fbinfo->fbops = &ubicom32plio80_ops; -+ ud->fbinfo->fix = ubicom32plio80_fix; -+ ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned; -+ ud->fbinfo->fix.smem_len = vram_size * 1024; -+ ud->fbinfo->fix.line_length = xres * 2; -+ ud->fbinfo->fix.mmio_start = (u32)ud; -+ ud->fbinfo->fix.mmio_len = sizeof(struct ubicom32plio80_drvdata); -+ -+ /* -+ * We support panning in the y direction only -+ */ -+ ud->fbinfo->fix.xpanstep = 0; -+ ud->fbinfo->fix.ypanstep = 1; -+ -+ ud->fbinfo->pseudo_palette = ud->pseudo_palette; -+ ud->fbinfo->flags = FBINFO_DEFAULT; -+ ud->fbinfo->var = ubicom32plio80_var; -+ ud->fbinfo->var.xres = xres; -+ ud->fbinfo->var.yres = yres; -+ -+ /* -+ * We cannot pan in the X direction, so xres_virtual is xres -+ * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length -+ */ -+ ud->fbinfo->var.xres_virtual = xres; -+ ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length; -+ -+ /* -+ * Allocate a color map -+ */ -+ rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0); -+ if (rc) { -+ dev_err(dev, "Fail to allocate colormap (%d entries)\n", -+ PALETTE_ENTRIES_NO); -+ goto fail; -+ } -+ ud->cmap_alloc = true; -+ -+ /* -+ * Register new frame buffer -+ */ -+ rc = register_framebuffer(ud->fbinfo); -+ if (rc) { -+ dev_err(dev, "Could not register frame buffer\n"); -+ goto fail; -+ } -+ -+ /* -+ * request the PLIO IRQ -+ */ -+ rc = request_irq(TX_FIFO_INT(PLIO_PORT), ubicom32plio80_isr, IRQF_DISABLED, "ubicom32plio80", ud); -+ if (rc) { -+ dev_err(dev, "Could not request IRQ\n"); -+ goto fail; -+ } -+ ud->irq_req = 1; -+ -+ /* -+ * Clear any garbage out of the TX FIFOs (idif_txfifo_flush) -+ * -+ * cast through ubicom32_io_port to make sure the compiler does a word write -+ */ -+ ((struct ubicom32_io_port *)PLIO_NBR)->int_set = (1 << 18); -+ -+ /* -+ * Start up the state machine -+ */ -+ plio_init(&plio_fctl, &plio_config, (plio_sram_t *)ubicom32plio80_plio_fsm, sizeof(ubicom32plio80_plio_fsm)); -+ PLIO_NBR->fctl0.pfsm_cmd = 0; -+ -+ ubicom32plio80_update(ud, ud->fb_aligned); -+ -+ /* -+ * Tell the log we are here -+ */ -+ dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n", -+ ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres, -+ ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual); -+ -+ /* -+ * Success -+ */ -+ return 0; -+ -+fail: -+ ubicom32plio80_release(dev); -+ return rc; -+} -+ -+/* -+ * ubicom32plio80_platform_remove -+ */ -+static int ubicom32plio80_platform_remove(struct platform_device *pdev) -+{ -+ dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n"); -+ return ubicom32plio80_release(&pdev->dev); -+} -+ -+static struct platform_driver ubicom32plio80_platform_driver = { -+ .probe = ubicom32plio80_platform_probe, -+ .remove = ubicom32plio80_platform_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+#ifndef MODULE -+/* -+ * ubicom32plio80_setup -+ * Process kernel boot options -+ */ -+static int __init ubicom32plio80_setup(char *options) -+{ -+ char *this_opt; -+ -+ if (!options || !*options) { -+ return 0; -+ } -+ -+ while ((this_opt = strsep(&options, ",")) != NULL) { -+ if (!*this_opt) { -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "vram_size=", 10)) { -+ vram_size = simple_strtoul(this_opt + 10, NULL, 0); -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "bgr=", 4)) { -+ bgr = simple_strtoul(this_opt + 4, NULL, 0); -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "xres=", 5)) { -+ xres = simple_strtoul(this_opt + 5, NULL, 0); -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "yres=", 5)) { -+ yres = simple_strtoul(this_opt + 5, NULL, 0); -+ continue; -+ } -+ } -+ return 0; -+} -+#endif /* MODULE */ -+ -+/* -+ * ubicom32plio80_init -+ */ -+static int __devinit ubicom32plio80_init(void) -+{ -+ int ret; -+ -+#ifndef MODULE -+ /* -+ * Get kernel boot options (in 'video=ubicom32plio80:') -+ */ -+ char *option = NULL; -+ -+ if (fb_get_options(DRIVER_NAME, &option)) { -+ return -ENODEV; -+ } -+ ubicom32plio80_setup(option); -+#endif /* MODULE */ -+ -+ ret = platform_driver_register(&ubicom32plio80_platform_driver); -+ -+ if (!ret) { -+ ubicom32plio80_platform_device = platform_device_alloc(DRIVER_NAME, 0); -+ -+ if (ubicom32plio80_platform_device) -+ ret = platform_device_add(ubicom32plio80_platform_device); -+ else -+ ret = -ENOMEM; -+ -+ if (ret) { -+ platform_device_put(ubicom32plio80_platform_device); -+ platform_driver_unregister(&ubicom32plio80_platform_driver); -+ } -+ } -+ -+ return ret; -+} -+module_init(ubicom32plio80_init); -+ -+/* -+ * ubicom32plio80_exit -+ */ -+static void __exit ubicom32plio80_exit(void) -+{ -+ platform_device_unregister(ubicom32plio80_platform_device); -+ platform_driver_unregister(&ubicom32plio80_platform_driver); -+} -+module_exit(ubicom32plio80_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); -+MODULE_DESCRIPTION(DRIVER_DESCRIPTION); -diff -ruN linux-2.6.30.10/drivers/video/ubicom32vfb.c linux-2.6.30.10-ubi/drivers/video/ubicom32vfb.c ---- linux-2.6.30.10/drivers/video/ubicom32vfb.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/video/ubicom32vfb.c 2009-12-11 11:45:21.000000000 +0200 -@@ -0,0 +1,603 @@ -+/* -+ * drivers/video/ubicom32vfb.c -+ * Ubicom32 virtual frame buffer driver -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+/* -+ * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by -+ * Geert Uytterhoeven. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_NAME "ubicom32vfb" -+#define DRIVER_DESCRIPTION "Ubicom32 virtual frame buffer driver" -+ -+#define PALETTE_ENTRIES_NO 16 -+ -+/* -+ * Option variables -+ * -+ * vram_size: VRAM size in kilobytes, subject to alignment -+ */ -+static int vram_size = 0; -+module_param(vram_size, int, 0); -+MODULE_PARM_DESC(vram_size, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment"); -+ -+static int xres = 320; -+module_param(xres, int, 0); -+MODULE_PARM_DESC(xres, "x (horizontal) resolution"); -+ -+static int yres = 240; -+module_param(yres, int, 0); -+MODULE_PARM_DESC(yres, "y (vertical) resolution"); -+ -+static int bgr = 0; -+module_param(bgr, int, 0); -+MODULE_PARM_DESC(bgr, "display is BGR (Blue is MSB)"); -+ -+#define BITS_PER_PIXEL 16 -+ -+/* -+ * Buffer alignment, must not be 0 -+ */ -+#define UBICOM32VFB_ALIGNMENT 4 -+ -+/* -+ * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in. -+ */ -+static struct fb_fix_screeninfo ubicom32vfb_fix = { -+ .id = "Ubicom32", -+ .type = FB_TYPE_PACKED_PIXELS, -+ .visual = FB_VISUAL_TRUECOLOR, -+ .accel = FB_ACCEL_UBICOM32_VFB, -+}; -+ -+/* -+ * Filled in at probe time when we find out what the hardware supports -+ */ -+static struct fb_var_screeninfo ubicom32vfb_var; -+ -+/* -+ * Private data structure -+ */ -+struct ubicom32vfb_drvdata { -+ struct fb_info *fbinfo; -+ bool cmap_alloc; -+ -+ /* -+ * The address of the framebuffer in memory -+ */ -+ void *fb; -+ void *fb_aligned; -+ -+ /* -+ * Total size of vram including alignment allowance -+ */ -+ u32 total_vram_size; -+ -+ /* -+ * Fake palette of 16 colors -+ */ -+ u32 pseudo_palette[PALETTE_ENTRIES_NO]; -+}; -+ -+static struct platform_device *ubicom32vfb_platform_device; -+ -+/* -+ * ubicom32vfb_pan_display -+ * Pans the display to a given location. Supports only y direction panning. -+ */ -+static int ubicom32vfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) -+{ -+ struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)fbi->par; -+ void *new_addr; -+ -+ /* -+ * Get the last y line that would be displayed. Since we don't support YWRAP, -+ * it must be less than our virtual y size. -+ */ -+ u32 lasty = var->yoffset + var->yres; -+ if (lasty > fbi->var.yres_virtual) { -+ /* -+ * We would fall off the end of our frame buffer if we panned here. -+ */ -+ return -EINVAL; -+ } -+ -+ if (var->xoffset) { -+ /* -+ * We don't support panning in the x direction -+ */ -+ return -EINVAL; -+ } -+ -+ /* -+ * Everything looks sane, go ahead and pan -+ * -+ * We have to calculate a new address for the VDC to look at -+ */ -+ new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32vfb_setcolreg -+ * Sets a color in our virtual palette -+ */ -+static int ubicom32vfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi) -+{ -+ u32 *palette = fbi->pseudo_palette; -+ -+ if (regno >= PALETTE_ENTRIES_NO) { -+ return -EINVAL; -+ } -+ -+ /* -+ * We only use 8 bits from each color -+ */ -+ red >>= 8; -+ green >>= 8; -+ blue >>= 8; -+ -+ /* -+ * Convert any grayscale values -+ */ -+ if (fbi->var.grayscale) { -+ u16 gray = red + green + blue; -+ gray += (gray >> 2) + (gray >> 3) - (gray >> 7); -+ gray >>= 2; -+ if (gray > 255) { -+ gray = 255; -+ } -+ red = gray; -+ blue = gray; -+ green = gray; -+ } -+ -+ palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) | -+ (blue << fbi->var.blue.offset); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32vfb_mmap -+ */ -+static int ubicom32vfb_mmap(struct fb_info *info, struct vm_area_struct *vma) -+{ -+ struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)info->par; -+ -+ vma->vm_start = (unsigned long)(ud->fb_aligned); -+ -+ vma->vm_end = vma->vm_start + info->fix.smem_len; -+ -+ /* For those who don't understand how mmap works, go read -+ * Documentation/nommu-mmap.txt. -+ * For those that do, you will know that the VM_MAYSHARE flag -+ * must be set in the vma->vm_flags structure on noMMU -+ * Other flags can be set, and are documented in -+ * include/linux/mm.h -+ */ -+ -+ vma->vm_flags |= VM_MAYSHARE | VM_SHARED; -+ -+ return 0; -+} -+ -+/* -+ * ubicom32vfb_check_var -+ * Check the var, tweak it but don't change operational parameters. -+ */ -+static int ubicom32vfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)info->par; -+ u32 line_size = var->xres * (BITS_PER_PIXEL / 8); -+ -+ /* -+ * See if we can handle this bpp -+ */ -+ if (var->bits_per_pixel > BITS_PER_PIXEL) { -+ return -EINVAL; -+ } -+ var->bits_per_pixel = BITS_PER_PIXEL; -+ -+ /* -+ * See if we have enough memory to handle this resolution -+ */ -+ if ((line_size * var->yres * BITS_PER_PIXEL / 8) > ud->total_vram_size) { -+ return -EINVAL; -+ } -+ -+ var->xres_virtual = var->xres; -+ var->yres_virtual = ud->total_vram_size / line_size; -+ -+ var->red.length = 5; -+ var->green.length = 6; -+ var->green.offset = 5; -+ var->blue.length = 5; -+ var->transp.offset = var->transp.length = 0; -+ -+ if (bgr) { -+ var->red.offset = 0; -+ var->blue.offset = 11; -+ } else { -+ var->red.offset = 11; -+ var->blue.offset = 0; -+ } -+ -+ var->nonstd = 0; -+ var->height = -1; -+ var->width = -1; -+ var->vmode = FB_VMODE_NONINTERLACED; -+ var->sync = 0; -+ -+ return 0; -+} -+ -+/* -+ * ubicom32vfb_set_par -+ * Set the video mode according to info->var -+ */ -+static int ubicom32vfb_set_par(struct fb_info *info) -+{ -+ /* -+ * Anything changed? -+ */ -+ if ((xres == info->var.xres) && (yres == info->var.yres)) { -+ return 0; -+ } -+ -+ /* -+ * Implement changes -+ */ -+ xres = info->var.xres; -+ yres = info->var.yres; -+ info->fix.visual = FB_VISUAL_TRUECOLOR; -+ info->fix.xpanstep = 0; -+ info->fix.ypanstep = 1; -+ info->fix.line_length = xres * (BITS_PER_PIXEL / 8); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32vfb_ops -+ * List of supported operations -+ */ -+static struct fb_ops ubicom32vfb_ops = -+{ -+ .owner = THIS_MODULE, -+ .fb_pan_display = ubicom32vfb_pan_display, -+ .fb_setcolreg = ubicom32vfb_setcolreg, -+ .fb_mmap = ubicom32vfb_mmap, -+ .fb_check_var = ubicom32vfb_check_var, -+ .fb_set_par = ubicom32vfb_set_par, -+ .fb_fillrect = cfb_fillrect, -+ .fb_copyarea = cfb_copyarea, -+ .fb_imageblit = cfb_imageblit, -+}; -+ -+/* -+ * ubicom32vfb_release -+ */ -+static int ubicom32vfb_release(struct device *dev) -+{ -+ struct ubicom32vfb_drvdata *ud = dev_get_drvdata(dev); -+ -+ unregister_framebuffer(ud->fbinfo); -+ -+ if (ud->cmap_alloc) { -+ fb_dealloc_cmap(&ud->fbinfo->cmap); -+ } -+ -+ if (ud->fb) { -+ kfree(ud->fb); -+ } -+ -+ framebuffer_release(ud->fbinfo); -+ dev_set_drvdata(dev, NULL); -+ -+ return 0; -+} -+ -+/* -+ * ubicom32vfb_platform_probe -+ */ -+static int __init ubicom32vfb_platform_probe(struct platform_device *pdev) -+{ -+ struct ubicom32vfb_drvdata *ud; -+ struct fb_info *fbinfo; -+ int rc; -+ size_t fbsize; -+ struct device *dev = &pdev->dev; -+ int offset; -+ -+ /* -+ * This is the minimum VRAM size -+ */ -+ fbsize = xres * yres * 2; -+ if (!vram_size) { -+ vram_size = (fbsize + 1023) / 1024; -+ } else { -+ if (fbsize > (vram_size * 1024)) { -+ dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize); -+ return -ENOMEM; // should be ebadparam? -+ } -+ } -+ -+ /* -+ * Allocate the framebuffer instance + our private data -+ */ -+ fbinfo = framebuffer_alloc(sizeof(struct ubicom32vfb_drvdata), &pdev->dev); -+ if (!fbinfo) { -+ dev_err(dev, "Not enough memory to allocate instance.\n"); -+ return -ENOMEM; -+ } -+ -+ /* -+ * Fill in our private data. -+ */ -+ ud = (struct ubicom32vfb_drvdata *)fbinfo->par; -+ ud->fbinfo = fbinfo; -+ dev_set_drvdata(dev, ud); -+ -+ /* -+ * Allocate and align the requested amount of VRAM -+ */ -+ ud->total_vram_size = (vram_size * 1024) + UBICOM32VFB_ALIGNMENT; -+ ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL); -+ if (ud->fb == NULL) { -+ dev_err(dev, "Couldn't allocate VRAM\n"); -+ rc = -ENOMEM; -+ goto fail; -+ } -+ -+ offset = (u32_t)ud->fb & (UBICOM32VFB_ALIGNMENT - 1); -+ if (!offset) { -+ ud->fb_aligned = ud->fb; -+ } else { -+ offset = UBICOM32VFB_ALIGNMENT - offset; -+ ud->fb_aligned = ud->fb + offset; -+ } -+ -+ /* -+ * Clear the entire frame buffer -+ */ -+ memset(ud->fb_aligned, 0, vram_size * 1024); -+ -+ /* -+ * Fill in the fb_var_screeninfo structure -+ */ -+ memset(&ubicom32vfb_var, 0, sizeof(ubicom32vfb_var)); -+ ubicom32vfb_var.bits_per_pixel = BITS_PER_PIXEL; -+ ubicom32vfb_var.red.length = 5; -+ ubicom32vfb_var.green.length = 6; -+ ubicom32vfb_var.green.offset = 5; -+ ubicom32vfb_var.blue.length = 5; -+ ubicom32vfb_var.activate = FB_ACTIVATE_NOW; -+ -+ if (bgr) { -+ ubicom32vfb_var.red.offset = 0; -+ ubicom32vfb_var.blue.offset = 11; -+ } else { -+ ubicom32vfb_var.red.offset = 11; -+ ubicom32vfb_var.blue.offset = 0; -+ } -+ -+ /* -+ * Fill in the fb_info structure -+ */ -+ ud->fbinfo->device = dev; -+ ud->fbinfo->screen_base = (void *)ud->fb_aligned; -+ ud->fbinfo->fbops = &ubicom32vfb_ops; -+ ud->fbinfo->fix = ubicom32vfb_fix; -+ ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned; -+ ud->fbinfo->fix.smem_len = vram_size * 1024; -+ ud->fbinfo->fix.line_length = xres * 2; -+ ud->fbinfo->fix.mmio_start = (u32)ud; -+ ud->fbinfo->fix.mmio_len = sizeof(struct ubicom32vfb_drvdata); -+ -+ /* -+ * We support panning in the y direction only -+ */ -+ ud->fbinfo->fix.xpanstep = 0; -+ ud->fbinfo->fix.ypanstep = 1; -+ -+ ud->fbinfo->pseudo_palette = ud->pseudo_palette; -+ ud->fbinfo->flags = FBINFO_DEFAULT; -+ ud->fbinfo->var = ubicom32vfb_var; -+ ud->fbinfo->var.xres = xres; -+ ud->fbinfo->var.yres = yres; -+ -+ /* -+ * We cannot pan in the X direction, so xres_virtual is xres -+ * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length -+ */ -+ ud->fbinfo->var.xres_virtual = xres; -+ ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length; -+ -+ /* -+ * Allocate a color map -+ */ -+ rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0); -+ if (rc) { -+ dev_err(dev, "Fail to allocate colormap (%d entries)\n", -+ PALETTE_ENTRIES_NO); -+ goto fail; -+ } -+ ud->cmap_alloc = true; -+ -+ /* -+ * Register new frame buffer -+ */ -+ rc = register_framebuffer(ud->fbinfo); -+ if (rc) { -+ dev_err(dev, "Could not register frame buffer\n"); -+ goto fail; -+ } -+ -+ /* -+ * Tell the log we are here -+ */ -+ dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n", -+ ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres, -+ ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual); -+ -+ /* -+ * Success -+ */ -+ return 0; -+ -+fail: -+ ubicom32vfb_release(dev); -+ return rc; -+} -+ -+/* -+ * ubicom32vfb_platform_remove -+ */ -+static int ubicom32vfb_platform_remove(struct platform_device *pdev) -+{ -+ dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n"); -+ return ubicom32vfb_release(&pdev->dev); -+} -+ -+static struct platform_driver ubicom32vfb_platform_driver = { -+ .probe = ubicom32vfb_platform_probe, -+ .remove = ubicom32vfb_platform_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+#ifndef MODULE -+/* -+ * ubicom32vfb_setup -+ * Process kernel boot options -+ */ -+static int __init ubicom32vfb_setup(char *options) -+{ -+ char *this_opt; -+ -+ if (!options || !*options) { -+ return 0; -+ } -+ -+ while ((this_opt = strsep(&options, ",")) != NULL) { -+ if (!*this_opt) { -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "vram_size=", 10)) { -+ vram_size = simple_strtoul(this_opt + 10, NULL, 0); -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "bgr=", 4)) { -+ bgr = simple_strtoul(this_opt + 4, NULL, 0); -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "xres=", 5)) { -+ xres = simple_strtoul(this_opt + 5, NULL, 0); -+ continue; -+ } -+ -+ if (!strncmp(this_opt, "yres=", 5)) { -+ yres = simple_strtoul(this_opt + 5, NULL, 0); -+ continue; -+ } -+ } -+ return 0; -+} -+#endif /* MODULE */ -+ -+/* -+ * ubicom32vfb_init -+ */ -+static int __devinit ubicom32vfb_init(void) -+{ -+ int ret; -+ -+#ifndef MODULE -+ /* -+ * Get kernel boot options (in 'video=ubicom32vfb:') -+ */ -+ char *option = NULL; -+ -+ if (fb_get_options(DRIVER_NAME, &option)) { -+ return -ENODEV; -+ } -+ ubicom32vfb_setup(option); -+#endif /* MODULE */ -+ -+ ret = platform_driver_register(&ubicom32vfb_platform_driver); -+ -+#ifdef CONFIG_FB_UBICOM32_VIRTUAL_NOAUTO -+ return ret; -+#else -+ if (!ret) { -+ ubicom32vfb_platform_device = platform_device_alloc(DRIVER_NAME, 0); -+ -+ if (ubicom32vfb_platform_device) -+ ret = platform_device_add(ubicom32vfb_platform_device); -+ else -+ ret = -ENOMEM; -+ -+ if (ret) { -+ platform_device_put(ubicom32vfb_platform_device); -+ platform_driver_unregister(&ubicom32vfb_platform_driver); -+ } -+ } -+ -+ return ret; -+#endif -+} -+module_init(ubicom32vfb_init); -+ -+/* -+ * ubicom32vfb_exit -+ */ -+static void __exit ubicom32vfb_exit(void) -+{ -+ platform_device_unregister(ubicom32vfb_platform_device); -+ platform_driver_unregister(&ubicom32vfb_platform_driver); -+} -+module_exit(ubicom32vfb_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); -+MODULE_DESCRIPTION(DRIVER_DESCRIPTION); -diff -ruN linux-2.6.30.10/drivers/watchdog/Kconfig linux-2.6.30.10-ubi/drivers/watchdog/Kconfig ---- linux-2.6.30.10/drivers/watchdog/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/watchdog/Kconfig 2009-12-11 11:45:21.000000000 +0200 -@@ -887,6 +887,19 @@ +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -887,6 +887,19 @@ config WATCHDOG_RIO machines. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. @@ -55413,10 +1301,9 @@ diff -ruN linux-2.6.30.10/drivers/watchdog/Kconfig linux-2.6.30.10-ubi/drivers/w # XTENSA Architecture # -diff -ruN linux-2.6.30.10/drivers/watchdog/Makefile linux-2.6.30.10-ubi/drivers/watchdog/Makefile ---- linux-2.6.30.10/drivers/watchdog/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/watchdog/Makefile 2009-12-11 11:45:21.000000000 +0200 -@@ -131,6 +131,9 @@ +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -131,6 +131,9 @@ obj-$(CONFIG_SH_WDT) += shwdt.o obj-$(CONFIG_WATCHDOG_RIO) += riowd.o obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o @@ -55426,643 +1313,8 @@ diff -ruN linux-2.6.30.10/drivers/watchdog/Makefile linux-2.6.30.10-ubi/drivers/ # XTENSA Architecture # Architecture Independant -diff -ruN linux-2.6.30.10/drivers/watchdog/ubi32_wdt.c linux-2.6.30.10-ubi/drivers/watchdog/ubi32_wdt.c ---- linux-2.6.30.10/drivers/watchdog/ubi32_wdt.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/drivers/watchdog/ubi32_wdt.c 2009-12-11 11:45:21.000000000 +0200 -@@ -0,0 +1,630 @@ -+/* -+ * drivers/watchdog/ubi32_wdt.c -+ * Ubicom32 Watchdog Driver -+ * -+ * Originally based on softdog.c -+ * Copyright 2006-2007 Analog Devices Inc. -+ * Copyright 2006-2007 Michele d'Amico -+ * Copyright 1996 Alan Cox -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define WATCHDOG_NAME "ubi32-wdt" -+#define PFX WATCHDOG_NAME ": " -+ -+#define OSC1_FREQ 12000000 -+#define WATCHDOG_SEC_TO_CYC(x) (OSC1_FREQ * (x)) -+#define WATCHDOG_MAX_SEC (0xffffffff / OSC1_FREQ) -+ -+#define MIN_PROCESSOR_ADDRESS 0x03000000 -+ -+static DEFINE_SPINLOCK(ubi32_wdt_spinlock); -+ -+#define WATCHDOG_TIMEOUT 20 -+ -+#if defined(CONFIG_WATCHDOG_NOWAYOUT) -+#define WATCHDOG_NOWAYOUT 1 -+#else -+#define WATCHDOG_NOWAYOUT 0 -+#endif -+ -+static unsigned int timeout = WATCHDOG_TIMEOUT; -+static int nowayout = WATCHDOG_NOWAYOUT; -+static struct watchdog_info ubi32_wdt_info; -+static unsigned long open_check; -+static char expect_close; -+ -+#if !defined(CONFIG_SMP) -+#define UBI32_WDT_LOCK(lock, flags) local_irq_save(flags) -+#define UBI32_WDT_UNLOCK(lock, flags) local_irq_restore(flags) -+#define UBI32_WDT_LOCK_CHECK() -+#else -+#define UBI32_WDT_LOCK(lock, flags) spin_lock_irqsave((lock), (flags)); -+#define UBI32_WDT_UNLOCK(lock, flags) spin_unlock_irqrestore((lock), (flags)); -+#define UBI32_WDT_LOCK_CHECK() BUG_ON(!spin_is_locked(&ubi32_wdt_spinlock)); -+#endif -+ -+/* -+ * ubi32_wdt_remaining() -+ * Return the approximate number of seconds remaining -+ */ -+static int ubi32_wdt_remaining(void) -+{ -+ int compare; -+ int curr; -+ -+ UBI32_WDT_LOCK_CHECK(); -+ -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); -+ compare = ubicom32_read_reg(&UBICOM32_IO_TIMER->wdcom); -+ curr = ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); -+ return (compare - curr) / OSC1_FREQ; -+ -+} -+ -+/* -+ * ubi32_wdt_keepalive() -+ * Keep the Userspace Watchdog Alive -+ * -+ * The Userspace watchdog got a KeepAlive: schedule the next timeout. -+ */ -+static int ubi32_wdt_keepalive(void) -+{ -+ UBI32_WDT_LOCK_CHECK(); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcom, -+ ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval) -+ + WATCHDOG_SEC_TO_CYC(timeout)); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); -+ return 0; -+} -+ -+/* -+ * ubi32_wdt_stop() -+ * Stop the on-chip Watchdog -+ */ -+static int ubi32_wdt_stop(void) -+{ -+ UBI32_WDT_LOCK_CHECK(); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcfg, TIMER_WATCHDOG_DISABLE); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); -+ return 0; -+} -+ -+/* -+ * ubi32_wdt_start() -+ * Start the on-chip Watchdog -+ */ -+static int ubi32_wdt_start(void) -+{ -+ UBI32_WDT_LOCK_CHECK(); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcom, -+ ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval) -+ + WATCHDOG_SEC_TO_CYC(timeout)); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcfg, ~TIMER_WATCHDOG_DISABLE); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); -+ return 0; -+} -+ -+/* -+ * ubi32_wdt_running() -+ * Return true if the watchdog is configured -+ */ -+static int ubi32_wdt_running(void) -+{ -+ int enabled; -+ -+ UBI32_WDT_LOCK_CHECK(); -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL); -+ enabled = ubicom32_read_reg(&UBICOM32_IO_TIMER->wdcfg) == ~TIMER_WATCHDOG_DISABLE; -+ ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0); -+ return enabled; -+} -+ -+/* -+ * ubi32_wdt_set_timeout() -+ * Set the Userspace Watchdog timeout -+ * -+ * - @t: new timeout value (in seconds) -+ */ -+static int ubi32_wdt_set_timeout(unsigned long t) -+{ -+ UBI32_WDT_LOCK_CHECK(); -+ -+ if (t > WATCHDOG_MAX_SEC) { -+ printk(KERN_WARNING PFX "request to large: %ld [1-%d] sec)\n", t, WATCHDOG_MAX_SEC); -+ return -EINVAL; -+ } -+ -+ /* -+ * If we are running, then reset the time value so -+ * that the new value has an immediate effect. -+ */ -+ timeout = t; -+ if (ubi32_wdt_running()) { -+ ubi32_wdt_keepalive(); -+ } -+ return 0; -+} -+ -+/* -+ * ubi32_wdt_open() -+ * Open the Device -+ */ -+static int ubi32_wdt_open(struct inode *inode, struct file *file) -+{ -+ unsigned long flags; -+ -+ if (test_and_set_bit(0, &open_check)) -+ return -EBUSY; -+ -+ if (nowayout) -+ __module_get(THIS_MODULE); -+ -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ ubi32_wdt_start(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ -+ return nonseekable_open(inode, file); -+} -+ -+/* -+ * ubi32_wdt_close() -+ * Close the Device -+ */ -+static int ubi32_wdt_release(struct inode *inode, struct file *file) -+{ -+ unsigned long flags; -+ -+ /* -+ * If we don't expect a close, then the watchdog continues -+ * even though the device is closed. The caller will have -+ * a full timeout value to reopen the device and continue -+ * stroking it. -+ */ -+ if (expect_close != 42) { -+ printk(KERN_CRIT PFX -+ "Unexpected close, not stopping watchdog!\n"); -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ ubi32_wdt_keepalive(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ } else { -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ ubi32_wdt_stop(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ } -+ -+ expect_close = 0; -+ clear_bit(0, &open_check); -+ return 0; -+} -+ -+/* -+ * ubi32_wdt_write() -+ * Write to Device -+ * -+ * If the user writes nothing, nothing happens. -+ * If the user writes a V, then we expect a close and allow a release. -+ * If the user writes anything else, it is ignored. -+ */ -+static ssize_t ubi32_wdt_write(struct file *file, const char __user *data, -+ size_t len, loff_t *ppos) -+{ -+ size_t i; -+ unsigned long flags; -+ -+ /* -+ * Every write resets the expect_close. The last write -+ * must be a V to allow shutdown on close. -+ */ -+ expect_close = 0; -+ -+ /* -+ * Empty writes still ping. -+ */ -+ if (!len) { -+ goto ping; -+ } -+ -+ /* -+ * If nowayout is set, it does not matter if the caller -+ * is trying to send the magic 'V' we will not allow a -+ * close to stop us. -+ */ -+ if (nowayout) { -+ goto ping; -+ } -+ -+ /* -+ * See if the program wrote a 'V' and if so disable -+ * the watchdog on release. -+ */ -+ for (i = 0; i < len; i++) { -+ char c; -+ if (get_user(c, data + i)) { -+ return -EFAULT; -+ } -+ -+ if (c == 'V') { -+ expect_close = 42; -+ } -+ } -+ -+ping: -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ ubi32_wdt_keepalive(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ return len; -+} -+ -+/* -+ * ubi32_wdt_ioctl() -+ * Query the watchdog device. -+ * -+ * Query basic information from the device or ping it, as outlined by the -+ * watchdog API. -+ */ -+static long ubi32_wdt_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ int __user *p = argp; -+ -+ switch (cmd) { -+ case WDIOC_GETSUPPORT: -+ if (copy_to_user(argp, &ubi32_wdt_info, sizeof(ubi32_wdt_info))) { -+ return -EFAULT; -+ } -+ return 0; -+ -+ case WDIOC_GETSTATUS: { -+ unsigned long flags; -+ int running; -+ -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ running = ubi32_wdt_running(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ return running; -+ } -+ -+ case WDIOC_GETBOOTSTATUS: -+ return ubicom32_get_reset_reason(); -+ -+ case WDIOC_SETOPTIONS: { -+ unsigned long flags; -+ int options, ret = -EINVAL; -+ -+ /* -+ * The sample application does not pass a pointer -+ * but directly passes a value of 1 or 2; however -+ * all of the implementations (and thus probably -+ * the real applications) pass a pointer to a value. -+ * -+ * It should be noted that WDIOC_SETOPTIONS is defined as -+ * _IOR(WATCHDOG_IOCTL_BASE, 4, int), which means -+ * that it should be an int and NOT a pointer. -+ * -+ * TODO: Examine this code for future chips. -+ * TODO: Report the sample code defect. -+ */ -+ if ((int)p < MIN_PROCESSOR_ADDRESS) { -+ options = (int)p; -+ } else { -+ if (get_user(options, p)) -+ return -EFAULT; -+ } -+ -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ if (options & WDIOS_DISABLECARD) { -+ ubi32_wdt_stop(); -+ ret = 0; -+ } -+ if (options & WDIOS_ENABLECARD) { -+ ubi32_wdt_start(); -+ ret = 0; -+ } -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ return ret; -+ } -+ -+ case WDIOC_KEEPALIVE: { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ ubi32_wdt_keepalive(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ return 0; -+ } -+ -+ case WDIOC_SETTIMEOUT: { -+ int new_timeout; -+ unsigned long flags; -+ int ret = 0; -+ -+ if (get_user(new_timeout, p)) -+ return -EFAULT; -+ -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ ret = ubi32_wdt_set_timeout(new_timeout); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ return ret; -+ -+ } -+ -+ case WDIOC_GETTIMEOUT: -+ return put_user(timeout, p); -+ -+ case WDIOC_GETTIMELEFT: { -+ unsigned long flags; -+ int remaining = 0; -+ -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ remaining = ubi32_wdt_remaining(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ return put_user(remaining, p); -+ } -+ -+ default: -+ return -ENOTTY; -+ } -+} -+ -+/* -+ * ubi32_wdt_notify_sys() -+ * Notification callback function for system events. -+ * -+ * Turn off the watchdog during a SYS_DOWN or SYS_HALT. -+ */ -+static int ubi32_wdt_notify_sys(struct notifier_block *this, -+ unsigned long code, void *unused) -+{ -+ if (code == SYS_DOWN || code == SYS_HALT) { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ ubi32_wdt_stop(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ } -+ -+ return NOTIFY_DONE; -+} -+ -+#ifdef CONFIG_PM -+static int state_before_suspend; -+ -+/* -+ * ubi32_wdt_suspend() -+ * suspend the watchdog -+ * -+ * Remember if the watchdog was running and stop it. -+ */ -+static int ubi32_wdt_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ state_before_suspend = ubi32_wdt_running(); -+ ubi32_wdt_stop(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ -+ return 0; -+} -+ -+/* -+ * ubi32_wdt_resume() -+ * Resume the watchdog -+ * -+ * If the watchdog was running, turn it back on. -+ */ -+static int ubi32_wdt_resume(struct platform_device *pdev) -+{ -+ if (state_before_suspend) { -+ unsigned long flags; -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ ubi32_wdt_set_timeout(timeout); -+ ubi32_wdt_start(); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ } -+ -+ return 0; -+} -+#else -+# define ubi32_wdt_suspend NULL -+# define ubi32_wdt_resume NULL -+#endif -+ -+static const struct file_operations ubi32_wdt_fops = { -+ .owner = THIS_MODULE, -+ .llseek = no_llseek, -+ .write = ubi32_wdt_write, -+ .unlocked_ioctl = ubi32_wdt_ioctl, -+ .open = ubi32_wdt_open, -+ .release = ubi32_wdt_release, -+}; -+ -+static struct miscdevice ubi32_wdt_miscdev = { -+ .minor = WATCHDOG_MINOR, -+ .name = "watchdog", -+ .fops = &ubi32_wdt_fops, -+}; -+ -+static struct watchdog_info ubi32_wdt_info = { -+ .identity = "Ubicom32 Watchdog", -+ .options = WDIOF_SETTIMEOUT | -+ WDIOF_KEEPALIVEPING | -+ WDIOF_MAGICCLOSE, -+}; -+ -+static struct notifier_block ubi32_wdt_notifier = { -+ .notifier_call = ubi32_wdt_notify_sys, -+}; -+ -+/* -+ * ubi32_wdt_probe() -+ * Probe/register the watchdog module -+ * -+ * Registers the misc device and notifier handler. Actual device -+ * initialization is handled by ubi32_wdt_open(). -+ */ -+static int __devinit ubi32_wdt_probe(struct platform_device *pdev) -+{ -+ int ret; -+ -+ ret = register_reboot_notifier(&ubi32_wdt_notifier); -+ if (ret) { -+ printk(KERN_ERR PFX -+ "cannot register reboot notifier (err=%d)\n", ret); -+ return ret; -+ } -+ -+ ret = misc_register(&ubi32_wdt_miscdev); -+ if (ret) { -+ printk(KERN_ERR PFX -+ "cannot register miscdev on minor=%d (err=%d)\n", -+ WATCHDOG_MINOR, ret); -+ unregister_reboot_notifier(&ubi32_wdt_notifier); -+ return ret; -+ } -+ -+ printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n", -+ timeout, nowayout); -+ -+ return 0; -+} -+ -+/* -+ * ubi32_wdt_remove() -+ * Uninstall the module -+ * -+ * Unregisters the misc device and notifier handler. Actual device -+ * deinitialization is handled by ubi32_wdt_close(). -+ */ -+static int __devexit ubi32_wdt_remove(struct platform_device *pdev) -+{ -+ misc_deregister(&ubi32_wdt_miscdev); -+ unregister_reboot_notifier(&ubi32_wdt_notifier); -+ return 0; -+} -+ -+static struct platform_device *ubi32_wdt_device; -+ -+static struct platform_driver ubi32_wdt_driver = { -+ .probe = ubi32_wdt_probe, -+ .remove = __devexit_p(ubi32_wdt_remove), -+ .suspend = ubi32_wdt_suspend, -+ .resume = ubi32_wdt_resume, -+ .driver = { -+ .name = WATCHDOG_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+/* -+ * ubi32_wdt_init() -+ * Initialize the watchdog. -+ * -+ * Checks the module params and registers the platform device & driver. -+ * Real work is in the platform probe function. -+ */ -+static int __init ubi32_wdt_init(void) -+{ -+ unsigned long flags; -+ int ret; -+ -+ /* -+ * Check that the timeout value is within range -+ */ -+ spin_lock_irqsave(&ubi32_wdt_spinlock, flags); -+ ret = ubi32_wdt_set_timeout(timeout); -+ spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags); -+ if (ret) { -+ return ret; -+ } -+ -+ /* -+ * Since this is an on-chip device and needs no board-specific -+ * resources, we'll handle all the platform device stuff here. -+ */ -+ ret = platform_driver_register(&ubi32_wdt_driver); -+ if (ret) { -+ printk(KERN_ERR PFX "unable to register driver\n"); -+ return ret; -+ } -+ -+ ubi32_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0); -+ if (IS_ERR(ubi32_wdt_device)) { -+ printk(KERN_ERR PFX "unable to register device\n"); -+ platform_driver_unregister(&ubi32_wdt_driver); -+ return PTR_ERR(ubi32_wdt_device); -+ } -+ -+ return 0; -+} -+ -+/* -+ * ubi32_wdt_exit() -+ * Deinitialize module -+ * -+ * Back out the platform device & driver steps. Real work is in the -+ * platform remove function. -+ */ -+static void __exit ubi32_wdt_exit(void) -+{ -+ platform_device_unregister(ubi32_wdt_device); -+ platform_driver_unregister(&ubi32_wdt_driver); -+} -+ -+module_init(ubi32_wdt_init); -+module_exit(ubi32_wdt_exit); -+ -+MODULE_AUTHOR("Sol Kavy"); -+MODULE_DESCRIPTION("Ubicom32 Watchdog Device Driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -+ -+module_param(timeout, uint, 0); -+MODULE_PARM_DESC(timeout, -+ "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" -+ __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); -+ -+module_param(nowayout, int, 0); -+MODULE_PARM_DESC(nowayout, -+ "Watchdog cannot be stopped once started (default=" -+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c ---- linux-2.6.30.10/fs/binfmt_flat.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/fs/binfmt_flat.c 2009-12-11 11:45:21.000000000 +0200 +--- a/fs/binfmt_flat.c ++++ b/fs/binfmt_flat.c @@ -67,6 +67,11 @@ #define FLAT_DATA_ALIGN (sizeof(void *)) #endif @@ -56075,7 +1327,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c #define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ #define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ -@@ -436,6 +441,7 @@ +@@ -436,6 +441,7 @@ static int load_flat_file(struct linux_b loff_t fpos; unsigned long start_code, end_code; int ret; @@ -56083,7 +1335,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ inode = bprm->file->f_path.dentry->d_inode; -@@ -521,6 +527,7 @@ +@@ -521,6 +527,7 @@ static int load_flat_file(struct linux_b /* OK, This is the point of no return */ set_personality(PER_LINUX_32BIT); @@ -56091,7 +1343,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c } /* -@@ -535,6 +542,12 @@ +@@ -535,6 +542,12 @@ static int load_flat_file(struct linux_b * it all together. */ if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) { @@ -56104,7 +1356,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c /* * this should give us a ROM ptr, but if it doesn't we don't * really care -@@ -553,7 +566,7 @@ +@@ -553,7 +566,7 @@ static int load_flat_file(struct linux_b goto err; } @@ -56113,7 +1365,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c len = PAGE_ALIGN(len); down_write(¤t->mm->mmap_sem); realdatastart = do_mmap(0, 0, len, -@@ -572,6 +585,7 @@ +@@ -572,6 +585,7 @@ static int load_flat_file(struct linux_b datapos = ALIGN(realdatastart + MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN); @@ -56121,7 +1373,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n", (int)(data_len + bss_len + stack_len), (int)datapos); -@@ -600,7 +614,11 @@ +@@ -600,7 +614,11 @@ static int load_flat_file(struct linux_b memp_size = len; } else { @@ -56134,7 +1386,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c len = PAGE_ALIGN(len); down_write(¤t->mm->mmap_sem); textpos = do_mmap(0, 0, len, -@@ -616,10 +634,17 @@ +@@ -616,10 +634,17 @@ static int load_flat_file(struct linux_b goto err; } @@ -56152,7 +1404,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c reloc = (unsigned long *) (datapos + (ntohl(hdr->reloc_start) - text_len)); -@@ -659,7 +684,7 @@ +@@ -659,7 +684,7 @@ static int load_flat_file(struct linux_b } if (result >= (unsigned long)-4096) { printk("Unable to read code+data+bss, errno %d\n",(int)-result); @@ -56161,7 +1413,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c MAX_SHARED_LIBS * sizeof(unsigned long)); ret = result; goto err; -@@ -672,6 +697,9 @@ +@@ -672,6 +697,9 @@ static int load_flat_file(struct linux_b /* The main program needs a little extra setup in the task structure */ start_code = textpos + sizeof (struct flat_hdr); @@ -56171,7 +1423,7 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c end_code = textpos + text_len; if (id == 0) { current->mm->start_code = start_code; -@@ -800,6 +828,13 @@ +@@ -800,6 +828,13 @@ static int load_flat_file(struct linux_b return 0; err: @@ -56185,10 +1437,9 @@ diff -ruN linux-2.6.30.10/fs/binfmt_flat.c linux-2.6.30.10-ubi/fs/binfmt_flat.c return ret; } -diff -ruN linux-2.6.30.10/fs/Kconfig.binfmt linux-2.6.30.10-ubi/fs/Kconfig.binfmt ---- linux-2.6.30.10/fs/Kconfig.binfmt 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/fs/Kconfig.binfmt 2009-12-11 11:45:21.000000000 +0200 -@@ -30,7 +30,7 @@ +--- a/fs/Kconfig.binfmt ++++ b/fs/Kconfig.binfmt +@@ -30,7 +30,7 @@ config COMPAT_BINFMT_ELF config BINFMT_ELF_FDPIC bool "Kernel support for FDPIC ELF binaries" default y @@ -56197,9 +1448,8 @@ diff -ruN linux-2.6.30.10/fs/Kconfig.binfmt linux-2.6.30.10-ubi/fs/Kconfig.binfm help ELF FDPIC binaries are based on ELF, but allow the individual load segments of a binary to be located in memory independently of each -diff -ruN linux-2.6.30.10/include/asm-generic/resource.h linux-2.6.30.10-ubi/include/asm-generic/resource.h ---- linux-2.6.30.10/include/asm-generic/resource.h 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/include/asm-generic/resource.h 2009-12-11 11:45:23.000000000 +0200 +--- a/include/asm-generic/resource.h ++++ b/include/asm-generic/resource.h @@ -69,13 +69,16 @@ /* * boot-time rlimit defaults for the init task: @@ -56218,9 +1468,8 @@ diff -ruN linux-2.6.30.10/include/asm-generic/resource.h linux-2.6.30.10-ubi/inc [RLIMIT_RSS] = { RLIM_INFINITY, RLIM_INFINITY }, \ [RLIMIT_NPROC] = { 0, 0 }, \ [RLIMIT_NOFILE] = { INR_OPEN, INR_OPEN }, \ -diff -ruN linux-2.6.30.10/include/linux/elf-em.h linux-2.6.30.10-ubi/include/linux/elf-em.h ---- linux-2.6.30.10/include/linux/elf-em.h 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/include/linux/elf-em.h 2009-12-11 11:45:23.000000000 +0200 +--- a/include/linux/elf-em.h ++++ b/include/linux/elf-em.h @@ -41,6 +41,7 @@ * up with a final number. */ @@ -56229,10 +1478,9 @@ diff -ruN linux-2.6.30.10/include/linux/elf-em.h linux-2.6.30.10-ubi/include/lin /* Bogus old v850 magic number, used by old tools. */ #define EM_CYGNUS_V850 0x9080 -diff -ruN linux-2.6.30.10/include/linux/fb.h linux-2.6.30.10-ubi/include/linux/fb.h ---- linux-2.6.30.10/include/linux/fb.h 2009-12-14 12:16:53.000000000 +0200 -+++ linux-2.6.30.10-ubi/include/linux/fb.h 2009-12-14 12:16:56.000000000 +0200 -@@ -151,6 +151,10 @@ +--- a/include/linux/fb.h ++++ b/include/linux/fb.h +@@ -151,6 +151,10 @@ struct dentry; #define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */ #define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */ @@ -56243,10 +1491,9 @@ diff -ruN linux-2.6.30.10/include/linux/fb.h linux-2.6.30.10-ubi/include/linux/f struct fb_fix_screeninfo { char id[16]; /* identification string eg "TT Builtin" */ unsigned long smem_start; /* Start of frame buffer mem */ -diff -ruN linux-2.6.30.10/include/linux/if_ppp.h linux-2.6.30.10-ubi/include/linux/if_ppp.h ---- linux-2.6.30.10/include/linux/if_ppp.h 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/include/linux/if_ppp.h 2009-12-11 11:45:23.000000000 +0200 -@@ -114,14 +114,14 @@ +--- a/include/linux/if_ppp.h ++++ b/include/linux/if_ppp.h +@@ -114,14 +114,14 @@ struct pppol2tp_ioc_stats { __u16 tunnel_id; /* redundant */ __u16 session_id; /* if zero, get tunnel stats */ __u32 using_ipsec:1; /* valid only for session_id == 0 */ @@ -56269,10 +1516,9 @@ diff -ruN linux-2.6.30.10/include/linux/if_ppp.h linux-2.6.30.10-ubi/include/lin }; #define ifr__name b.ifr_ifrn.ifrn_name -diff -ruN linux-2.6.30.10/include/linux/oprofile.h linux-2.6.30.10-ubi/include/linux/oprofile.h ---- linux-2.6.30.10/include/linux/oprofile.h 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/include/linux/oprofile.h 2009-12-11 11:45:23.000000000 +0200 -@@ -99,6 +99,8 @@ +--- a/include/linux/oprofile.h ++++ b/include/linux/oprofile.h +@@ -99,6 +99,8 @@ void oprofile_add_sample(struct pt_regs */ void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, unsigned long event, int is_kernel); @@ -56281,9 +1527,8 @@ diff -ruN linux-2.6.30.10/include/linux/oprofile.h linux-2.6.30.10-ubi/include/l /* Use this instead when the PC value is not from the regs. Doesn't * backtrace. */ -diff -ruN linux-2.6.30.10/include/linux/serial_core.h linux-2.6.30.10-ubi/include/linux/serial_core.h ---- linux-2.6.30.10/include/linux/serial_core.h 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/include/linux/serial_core.h 2009-12-11 11:45:23.000000000 +0200 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h @@ -167,6 +167,9 @@ /* MAX3100 */ #define PORT_MAX3100 86 @@ -56294,10 +1539,9 @@ diff -ruN linux-2.6.30.10/include/linux/serial_core.h linux-2.6.30.10-ubi/includ #ifdef __KERNEL__ #include -diff -ruN linux-2.6.30.10/include/linux/slab.h linux-2.6.30.10-ubi/include/linux/slab.h ---- linux-2.6.30.10/include/linux/slab.h 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/include/linux/slab.h 2009-12-11 11:45:23.000000000 +0200 -@@ -317,4 +317,14 @@ +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -317,4 +317,14 @@ static inline void *kzalloc_node(size_t return kmalloc_node(size, flags | __GFP_ZERO, node); } @@ -56312,10 +1556,9 @@ diff -ruN linux-2.6.30.10/include/linux/slab.h linux-2.6.30.10-ubi/include/linux +extern int kmem_cache_block_info(char *name, struct kmem_cache_size_info *data, int max_data); + #endif /* _LINUX_SLAB_H */ -diff -ruN linux-2.6.30.10/init/Kconfig linux-2.6.30.10-ubi/init/Kconfig ---- linux-2.6.30.10/init/Kconfig 2009-12-14 13:00:08.000000000 +0200 -+++ linux-2.6.30.10-ubi/init/Kconfig 2009-12-14 13:00:11.000000000 +0200 -@@ -865,6 +865,12 @@ +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -865,6 +865,12 @@ config ELF_CORE help Enable support for generating core dumps. Disabling saves about 4k. @@ -56328,10 +1571,9 @@ diff -ruN linux-2.6.30.10/init/Kconfig linux-2.6.30.10-ubi/init/Kconfig config PCSPKR_PLATFORM bool "Enable PC-Speaker support" if EMBEDDED depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES -diff -ruN linux-2.6.30.10/kernel/module.c linux-2.6.30.10-ubi/kernel/module.c ---- linux-2.6.30.10/kernel/module.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/kernel/module.c 2009-12-11 11:45:24.000000000 +0200 -@@ -2688,6 +2688,9 @@ +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2688,6 +2688,9 @@ static int m_show(struct seq_file *m, vo /* Used by oprofile and other similar tools. */ seq_printf(m, " 0x%p", mod->module_core); @@ -56341,7 +1583,7 @@ diff -ruN linux-2.6.30.10/kernel/module.c linux-2.6.30.10-ubi/kernel/module.c /* Taints info */ if (mod->taints) seq_printf(m, " %s", module_flags(mod, buf)); -@@ -2840,8 +2843,12 @@ +@@ -2840,8 +2843,12 @@ void print_modules(void) printk("Modules linked in:"); /* Most callers should already have preempt disabled, but make sure */ preempt_disable(); @@ -56355,9 +1597,8 @@ diff -ruN linux-2.6.30.10/kernel/module.c linux-2.6.30.10-ubi/kernel/module.c preempt_enable(); if (last_unloaded_module[0]) printk(" [last unloaded: %s]", last_unloaded_module); -diff -ruN linux-2.6.30.10/kernel/sched_clock.c linux-2.6.30.10-ubi/kernel/sched_clock.c ---- linux-2.6.30.10/kernel/sched_clock.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/kernel/sched_clock.c 2009-12-11 11:45:24.000000000 +0200 +--- a/kernel/sched_clock.c ++++ b/kernel/sched_clock.c @@ -38,8 +38,7 @@ */ unsigned long long __attribute__((weak)) sched_clock(void) @@ -56368,10 +1609,9 @@ diff -ruN linux-2.6.30.10/kernel/sched_clock.c linux-2.6.30.10-ubi/kernel/sched_ } static __read_mostly int sched_clock_running; -diff -ruN linux-2.6.30.10/lib/Kconfig.debug linux-2.6.30.10-ubi/lib/Kconfig.debug ---- linux-2.6.30.10/lib/Kconfig.debug 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/lib/Kconfig.debug 2009-12-11 11:45:24.000000000 +0200 -@@ -621,7 +621,7 @@ +--- a/lib/Kconfig.debug ++++ b/lib/Kconfig.debug +@@ -621,7 +621,7 @@ config FRAME_POINTER bool "Compile the kernel with frame pointers" depends on DEBUG_KERNEL && \ (CRIS || M68K || M68KNOMMU || FRV || UML || \ @@ -56380,19 +1620,17 @@ diff -ruN linux-2.6.30.10/lib/Kconfig.debug linux-2.6.30.10-ubi/lib/Kconfig.debu ARCH_WANT_FRAME_POINTERS default y if (DEBUG_INFO && UML) || ARCH_WANT_FRAME_POINTERS help -diff -ruN linux-2.6.30.10/mm/Makefile linux-2.6.30.10-ubi/mm/Makefile ---- linux-2.6.30.10/mm/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/mm/Makefile 2009-12-11 11:45:24.000000000 +0200 -@@ -38,3 +38,5 @@ +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -38,3 +38,5 @@ obj-$(CONFIG_SMP) += allocpercpu.o endif obj-$(CONFIG_QUICKLIST) += quicklist.o obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o + +CFLAGS_slab.o := $(PROFILING) -O2 -diff -ruN linux-2.6.30.10/mm/slab.c linux-2.6.30.10-ubi/mm/slab.c ---- linux-2.6.30.10/mm/slab.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/mm/slab.c 2009-12-11 11:45:24.000000000 +0200 -@@ -4100,6 +4100,68 @@ +--- a/mm/slab.c ++++ b/mm/slab.c +@@ -4100,6 +4100,68 @@ out: #ifdef CONFIG_SLABINFO @@ -56461,10 +1699,9 @@ diff -ruN linux-2.6.30.10/mm/slab.c linux-2.6.30.10-ubi/mm/slab.c static void print_slabinfo_header(struct seq_file *m) { /* -diff -ruN linux-2.6.30.10/scripts/mod/file2alias.c linux-2.6.30.10-ubi/scripts/mod/file2alias.c ---- linux-2.6.30.10/scripts/mod/file2alias.c 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/scripts/mod/file2alias.c 2009-12-11 11:45:24.000000000 +0200 -@@ -774,6 +774,15 @@ +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -774,6 +774,15 @@ void handle_moddevtable(struct module *m + sym->st_value; } @@ -56480,10 +1717,9 @@ diff -ruN linux-2.6.30.10/scripts/mod/file2alias.c linux-2.6.30.10-ubi/scripts/m if (sym_is(symname, "__mod_pci_device_table")) do_table(symval, sym->st_size, sizeof(struct pci_device_id), "pci", -diff -ruN linux-2.6.30.10/sound/Kconfig linux-2.6.30.10-ubi/sound/Kconfig ---- linux-2.6.30.10/sound/Kconfig 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/Kconfig 2009-12-11 11:45:24.000000000 +0200 -@@ -82,6 +82,8 @@ +--- a/sound/Kconfig ++++ b/sound/Kconfig +@@ -82,6 +82,8 @@ source "sound/parisc/Kconfig" source "sound/soc/Kconfig" @@ -56492,10 +1728,9 @@ diff -ruN linux-2.6.30.10/sound/Kconfig linux-2.6.30.10-ubi/sound/Kconfig endif # SND menuconfig SOUND_PRIME -diff -ruN linux-2.6.30.10/sound/Makefile linux-2.6.30.10-ubi/sound/Makefile ---- linux-2.6.30.10/sound/Makefile 2009-12-04 08:00:07.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/Makefile 2009-12-11 11:45:24.000000000 +0200 -@@ -6,7 +6,7 @@ +--- a/sound/Makefile ++++ b/sound/Makefile +@@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmw obj-$(CONFIG_SOUND_PRIME) += oss/ obj-$(CONFIG_DMASOUND) += oss/ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ @@ -56504,2843 +1739,3 @@ diff -ruN linux-2.6.30.10/sound/Makefile linux-2.6.30.10-ubi/sound/Makefile obj-$(CONFIG_SND_AOA) += aoa/ # This one must be compilable even if sound is configured out -diff -ruN linux-2.6.30.10/sound/ubicom32/Kconfig linux-2.6.30.10-ubi/sound/ubicom32/Kconfig ---- linux-2.6.30.10/sound/ubicom32/Kconfig 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/ubicom32/Kconfig 2009-12-11 11:45:25.000000000 +0200 -@@ -0,0 +1,42 @@ -+# ALSA Ubicom32 drivers -+ -+menuconfig SND_UBI32 -+ tristate "Ubicom32 sound devices" -+ select SND_PCM -+ default n -+ help -+ Say Y here to include support for audio on the Ubicom32 platform. -+ To compile this driver as a module, say M here: the module will be -+ called snd_ubi32. -+ -+if SND_UBI32 -+ -+config SND_UBI32_AUDIO_GENERIC_CAPTURE -+ bool "Generic Capture Support" -+ default n -+ help -+ Use this option to support ADCs which don't require special drivers. -+ -+config SND_UBI32_AUDIO_GENERIC -+ bool "Generic Playback Support" -+ default n -+ help -+ Use this option to support DACs which don't require special drivers. -+ -+comment "I2C Based Codecs" -+ -+config SND_UBI32_AUDIO_CS4350 -+ bool "Cirrus Logic CS4350 DAC" -+ depends on I2C -+ default n -+ help -+ Support for the Cirrus Logic CS4350 DAC. -+ -+config SND_UBI32_AUDIO_CS4384 -+ bool "Cirrus Logic CS4384 DAC" -+ depends on I2C -+ default n -+ help -+ Support for the Cirrus Logic CS4384 DAC. -+ -+endif #SND_UBI32 -diff -ruN linux-2.6.30.10/sound/ubicom32/Makefile linux-2.6.30.10-ubi/sound/ubicom32/Makefile ---- linux-2.6.30.10/sound/ubicom32/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/ubicom32/Makefile 2009-12-11 11:45:25.000000000 +0200 -@@ -0,0 +1,41 @@ -+# -+# sound/ubicom32/Makefile -+# Makefile for ALSA -+# -+# (C) Copyright 2009, Ubicom, Inc. -+# -+# This file is part of the Ubicom32 Linux Kernel Port. -+# -+# The Ubicom32 Linux Kernel Port is free software: you can redistribute -+# it and/or modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation, either version 2 of the -+# License, or (at your option) any later version. -+# -+# The Ubicom32 Linux Kernel Port is distributed in the hope that it -+# will be useful, but WITHOUT ANY WARRANTY; without even the implied -+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with the Ubicom32 Linux Kernel Port. If not, -+# see . -+# -+# Ubicom32 implementation derived from (with many thanks): -+# arch/m68knommu -+# arch/blackfin -+# arch/parisc -+# -+ -+CFLAGS_ubi32.o += -O2 -+snd-ubi32-pcm-objs := ubi32-pcm.o -+snd-ubi32-generic-objs := ubi32-generic.o -+snd-ubi32-generic-capture-objs := ubi32-generic-capture.o -+snd-ubi32-cs4350-objs := ubi32-cs4350.o -+snd-ubi32-cs4384-objs := ubi32-cs4384.o -+ -+# Toplevel Module Dependency -+obj-$(CONFIG_SND_UBI32) += snd-ubi32-pcm.o -+obj-$(CONFIG_SND_UBI32_AUDIO_GENERIC) += snd-ubi32-generic.o -+obj-$(CONFIG_SND_UBI32_AUDIO_GENERIC_CAPTURE) += snd-ubi32-generic-capture.o -+obj-$(CONFIG_SND_UBI32_AUDIO_CS4350) += snd-ubi32-cs4350.o -+obj-$(CONFIG_SND_UBI32_AUDIO_CS4384) += snd-ubi32-cs4384.o -diff -ruN linux-2.6.30.10/sound/ubicom32/ubi32-cs4350.c linux-2.6.30.10-ubi/sound/ubicom32/ubi32-cs4350.c ---- linux-2.6.30.10/sound/ubicom32/ubi32-cs4350.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/ubicom32/ubi32-cs4350.c 2009-12-11 11:45:25.000000000 +0200 -@@ -0,0 +1,583 @@ -+/* -+ * sound/ubicom32/ubi32-cs4350.c -+ * Interface to ubicom32 virtual audio peripheral - using CS4350 DAC -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubi32.h" -+ -+#define DRIVER_NAME "snd-ubi32-cs4350" -+ -+/* -+ * Module properties -+ */ -+static const struct i2c_device_id snd_ubi32_cs4350_id[] = { -+ {"cs4350", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, ubicom32audio_id); -+ -+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ -+ -+/* -+ * The dB scale for the Cirrus Logic cs4350. The output range is from -+ * -127.5 dB to 0 dB. -+ */ -+static const DECLARE_TLV_DB_SCALE(snd_ubi32_cs4350_db, -12750, 50, 0); -+ -+#define ubi32_cs4350_mute_info snd_ctl_boolean_stereo_info -+ -+/* -+ * Private data for cs4350 chip -+ */ -+struct ubi32_cs4350_priv { -+ /* -+ * The current volume settings -+ */ -+ uint8_t volume[2]; -+ -+ /* -+ * Bitmask of mutes MSB (unused, ..., unused, right_ch, left_ch) LSB -+ */ -+ uint8_t mute; -+ -+ /* -+ * Lock to protect this struct because callbacks are not atomic. -+ */ -+ spinlock_t lock; -+}; -+ -+/* -+ * The info for the cs4350. The volume currently has one channel, -+ * and 255 possible settings. -+ */ -+static int ubi32_cs4350_volume_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 2; -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = 255; // 8 bits in cirrus logic cs4350 volume register -+ return 0; -+} -+ -+static int ubi32_cs4350_volume_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); -+ struct ubi32_cs4350_priv *cs4350_priv; -+ unsigned long flags; -+ -+ cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); -+ -+ spin_lock_irqsave(&cs4350_priv->lock, flags); -+ -+ ucontrol->value.integer.value[0] = cs4350_priv->volume[0]; -+ ucontrol->value.integer.value[1] = cs4350_priv->volume[1]; -+ -+ spin_unlock_irqrestore(&cs4350_priv->lock, flags); -+ -+ return 0; -+} -+ -+static int ubi32_cs4350_volume_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); -+ struct i2c_client *client = (struct i2c_client *)ubi32_priv->client; -+ struct ubi32_cs4350_priv *cs4350_priv; -+ unsigned long flags; -+ int ret, changed; -+ char send[2]; -+ uint8_t volume_reg_value_left, volume_reg_value_right; -+ -+ changed = 0; -+ -+ cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); -+ volume_reg_value_left = 255 - (ucontrol->value.integer.value[0] & 0xFF); -+ volume_reg_value_right = 255 - (ucontrol->value.integer.value[1] & 0xFF); -+ -+#if SND_UBI32_DEBUG -+ snd_printk(KERN_INFO "Setting volume: writing %d,%d to CS4350 volume registers\n", volume_reg_value_left, volume_reg_value_right); -+#endif -+ spin_lock_irqsave(&cs4350_priv->lock, flags); -+ -+ if (cs4350_priv->volume[0] != ucontrol->value.integer.value[0]) { -+ send[0] = 0x05; // left channel -+ send[1] = volume_reg_value_left; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n"); -+ return changed; -+ } -+ cs4350_priv->volume[0] = ucontrol->value.integer.value[0]; -+ changed = 1; -+ } -+ -+ if (cs4350_priv->volume[1] != ucontrol->value.integer.value[1]) { -+ send[0] = 0x06; // right channel -+ send[1] = volume_reg_value_right; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set channel B volume on CS4350\n"); -+ return changed; -+ } -+ cs4350_priv->volume[1] = ucontrol->value.integer.value[1]; -+ changed = 1; -+ } -+ -+ spin_unlock_irqrestore(&cs4350_priv->lock, flags); -+ -+ return changed; -+} -+ -+static struct snd_kcontrol_new ubi32_cs4350_volume __devinitdata = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "PCM Playback Volume", -+ .info = ubi32_cs4350_volume_info, -+ .get = ubi32_cs4350_volume_get, -+ .put = ubi32_cs4350_volume_put, -+ .tlv.p = snd_ubi32_cs4350_db, -+}; -+ -+static int ubi32_cs4350_mute_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); -+ struct ubi32_cs4350_priv *cs4350_priv; -+ unsigned long flags; -+ -+ cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); -+ -+ spin_lock_irqsave(&cs4350_priv->lock, flags); -+ -+ ucontrol->value.integer.value[0] = cs4350_priv->mute & 1; -+ ucontrol->value.integer.value[1] = (cs4350_priv->mute & (1 << 1)) ? 1 : 0; -+ -+ spin_unlock_irqrestore(&cs4350_priv->lock, flags); -+ -+ return 0; -+} -+ -+static int ubi32_cs4350_mute_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); -+ struct i2c_client *client = (struct i2c_client *)ubi32_priv->client; -+ struct ubi32_cs4350_priv *cs4350_priv; -+ unsigned long flags; -+ int ret, changed; -+ char send[2]; -+ char recv[1]; -+ uint8_t mute; -+ -+ changed = 0; -+ -+ cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); -+ -+ spin_lock_irqsave(&cs4350_priv->lock, flags); -+ -+ if ((cs4350_priv->mute & 1) != ucontrol->value.integer.value[0]) { -+ send[0] = 0x04; -+ ret = i2c_master_send(client, send, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed to write to mute register: channel 0\n"); -+ return changed; -+ } -+ -+ ret = i2c_master_recv(client, recv, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed to read mute register: channel 0\n"); -+ return changed; -+ } -+ -+ mute = recv[0]; -+ -+ if (ucontrol->value.integer.value[0]) { -+ cs4350_priv->mute |= 1; -+ mute &= ~(1 << 4); -+#if SND_UBI32_DEBUG -+ snd_printk(KERN_INFO "Unmuted channel A\n"); -+#endif -+ } else { -+ cs4350_priv->mute &= ~1; -+ mute |= (1 << 4); -+#if SND_UBI32_DEBUG -+ snd_printk(KERN_INFO "Muted channel A\n"); -+#endif -+ } -+ -+ send[0] = 0x04; -+ send[1] = mute; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n"); -+ return changed; -+ } -+ changed = 1; -+ } -+ -+ if (((cs4350_priv->mute & 2) >> 1) != ucontrol->value.integer.value[1]) { -+ send[0] = 0x04; -+ ret = i2c_master_send(client, send, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed to write to mute register: channel 1\n"); -+ return changed; -+ } -+ -+ ret = i2c_master_recv(client, recv, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed to read mute register: channel 1\n"); -+ return changed; -+ } -+ -+ mute = recv[0]; -+ -+ if (ucontrol->value.integer.value[1]) { -+ cs4350_priv->mute |= (1 << 1); -+ mute &= ~(1 << 3); -+#if SND_UBI32_DEBUG -+ snd_printk(KERN_INFO "Unmuted channel B\n"); -+#endif -+ } else { -+ cs4350_priv->mute &= ~(1 << 1); -+ mute |= (1 << 3); -+#if SND_UBI32_DEBUG -+ snd_printk(KERN_INFO "Muted channel B\n"); -+#endif -+ } -+ -+ send[0] = 0x04; -+ send[1] = mute; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n"); -+ return changed; -+ } -+ changed = 1; -+ } -+ -+ spin_unlock_irqrestore(&cs4350_priv->lock, flags); -+ -+ return changed; -+} -+ -+static struct snd_kcontrol_new ubi32_cs4350_mute __devinitdata = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .name = "PCM Playback Switch", -+ .info = ubi32_cs4350_mute_info, -+ .get = ubi32_cs4350_mute_get, -+ .put = ubi32_cs4350_mute_put, -+}; -+ -+/* -+ * snd_ubi32_cs4350_free -+ * Card private data free function -+ */ -+void snd_ubi32_cs4350_free(struct snd_card *card) -+{ -+ struct ubi32_snd_priv *ubi32_priv; -+ struct ubi32_cs4350_priv *cs4350_priv; -+ -+ ubi32_priv = card->private_data; -+ cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); -+ if (cs4350_priv) { -+ kfree(cs4350_priv); -+ } -+} -+ -+/* -+ * snd_ubi32_cs4350_dac_init -+ */ -+static int snd_ubi32_cs4350_dac_init(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ int ret; -+ char send[2]; -+ char recv[8]; -+ -+ /* -+ * Initialize the CS4350 DAC over the I2C interface -+ */ -+ snd_printk(KERN_INFO "Initializing CS4350 DAC\n"); -+ -+ /* -+ * Register 0x01: device/revid -+ */ -+ send[0] = 0x01; -+ ret = i2c_master_send(client, send, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed 1st attempt to write to CS4350 register 0x01\n"); -+ goto fail; -+ } -+ ret = i2c_master_recv(client, recv, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed initial read of CS4350 registers\n"); -+ goto fail; -+ } -+ snd_printk(KERN_INFO "CS4350 DAC Device/Rev: %08x\n", recv[0]); -+ -+ /* -+ * Register 0x02: Mode control -+ * I2S DIF[2:0] = 001, no De-Emphasis, Auto speed mode -+ */ -+ send[0] = 0x02; -+ send[1] = 0x10; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set CS4350 to I2S mode\n"); -+ goto fail; -+ } -+ -+ /* -+ * Register 0x05/0x06: Volume control -+ * Channel A volume set to 0 dB -+ * Channel B volume set to 0 dB -+ */ -+ send[0] = 0x05; -+ send[1] = 0x00; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n"); -+ goto fail; -+ } -+ -+ send[0] = 0x06; -+ send[1] = 0x00; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n"); -+ goto fail; -+ } -+ -+ /* -+ * Make sure the changes took place, this helps verify we are talking to -+ * the correct chip. -+ */ -+ send[0] = 0x81; -+ ret = i2c_master_send(client, send, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed to initiate readback\n"); -+ goto fail; -+ } -+ -+ ret = i2c_master_recv(client, recv, 8); -+ if (ret != 8) { -+ snd_printk(KERN_ERR "Failed second read of CS4350 registers\n"); -+ goto fail; -+ } -+ -+ if ((recv[1] != 0x10) || (recv[4] != 0x00) || (recv[5] != 0x00)) { -+ snd_printk(KERN_ERR "Failed to initialize CS4350 DAC\n"); -+ goto fail; -+ } -+ -+ snd_printk(KERN_INFO "CS4350 DAC Initialized\n"); -+ return 0; -+ -+fail: -+ return -ENODEV; -+} -+ -+/* -+ * snd_ubi32_cs4350_i2c_probe -+ */ -+static int snd_ubi32_cs4350_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct snd_card *card; -+ struct ubi32_snd_priv *ubi32_priv; -+ struct ubi32_cs4350_priv *cs4350_priv; -+ int err, ret; -+ struct platform_device *pdev; -+ -+ pdev = client->dev.platform_data; -+ if (!pdev) { -+ return -ENODEV; -+ } -+ -+ /* -+ * Initialize the CS4350 DAC -+ */ -+ ret = snd_ubi32_cs4350_dac_init(client, id); -+ if (ret < 0) { -+ /* -+ * Initialization failed. Propagate the error. -+ */ -+ return ret; -+ } -+ -+ /* -+ * Create a snd_card structure -+ */ -+ card = snd_card_new(index, "Ubi32-CS4350", THIS_MODULE, sizeof(struct ubi32_snd_priv)); -+ if (card == NULL) { -+ return -ENOMEM; -+ } -+ -+ card->private_free = snd_ubi32_cs4350_free; /* Not sure if correct */ -+ ubi32_priv = card->private_data; -+ -+ /* -+ * CS4350 DAC has a minimum sample rate of 30khz and an -+ * upper limit of 216khz for it's auto-detect. -+ */ -+ ubi32_priv->min_sample_rate = 30000; -+ ubi32_priv->max_sample_rate = 216000; -+ -+ /* -+ * Initialize the snd_card's private data structure -+ */ -+ ubi32_priv->card = card; -+ ubi32_priv->client = client; -+ -+ /* -+ * Create our private data structure -+ */ -+ cs4350_priv = kzalloc(sizeof(struct ubi32_cs4350_priv), GFP_KERNEL); -+ if (!cs4350_priv) { -+ snd_card_free(card); -+ return -ENOMEM; -+ } -+ snd_ubi32_priv_set_drv(ubi32_priv, cs4350_priv); -+ spin_lock_init(&cs4350_priv->lock); -+ -+ /* -+ * Initial volume is set to max by probe function -+ */ -+ cs4350_priv->volume[0] = 0xFF; -+ cs4350_priv->volume[1] = 0xFF; -+ -+ /* -+ * The CS4350 starts off unmuted (bit set = not muted) -+ */ -+ cs4350_priv->mute = 3; -+ -+ /* -+ * Create the new PCM instance -+ */ -+ err = snd_ubi32_pcm_probe(ubi32_priv, pdev); -+ if (err < 0) { -+ snd_card_free(card); -+ return err; /* What is err? Need to include correct file */ -+ } -+ -+ strcpy(card->driver, "Ubi32-CS4350"); -+ strcpy(card->shortname, "Ubi32-CS4350"); -+ snprintf(card->longname, sizeof(card->longname), -+ "%s at sendirq=%d.%d recvirq=%d.%d regs=%p", -+ card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx, -+ ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr); -+ -+ snd_card_set_dev(card, &client->dev); -+ -+ /* -+ * Set up the mixer components -+ */ -+ err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_volume, ubi32_priv)); -+ if (err) { -+ snd_printk(KERN_WARNING "Failed to add volume mixer control\n"); -+ } -+ err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_mute, ubi32_priv)); -+ if (err) { -+ snd_printk(KERN_WARNING "Failed to add mute mixer control\n"); -+ } -+ -+ /* -+ * Register the sound card -+ */ -+ if ((err = snd_card_register(card)) != 0) { -+ snd_printk(KERN_WARNING "snd_card_register error\n"); -+ } -+ -+ /* -+ * Store card for access from other methods -+ */ -+ i2c_set_clientdata(client, card); -+ -+ return 0; -+} -+ -+/* -+ * snd_ubi32_cs4350_i2c_remove -+ */ -+static int __devexit snd_ubi32_cs4350_i2c_remove(struct i2c_client *client) -+{ -+ struct snd_card *card; -+ struct ubi32_snd_priv *ubi32_priv; -+ -+ card = i2c_get_clientdata(client); -+ -+ ubi32_priv = card->private_data; -+ snd_ubi32_pcm_remove(ubi32_priv); -+ -+ snd_card_free(i2c_get_clientdata(client)); -+ i2c_set_clientdata(client, NULL); -+ -+ return 0; -+} -+ -+/* -+ * I2C driver description -+ */ -+static struct i2c_driver snd_ubi32_cs4350_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ .id_table = snd_ubi32_cs4350_id, -+ .probe = snd_ubi32_cs4350_i2c_probe, -+ .remove = __devexit_p(snd_ubi32_cs4350_i2c_remove), -+}; -+ -+/* -+ * Driver init -+ */ -+static int __init snd_ubi32_cs4350_init(void) -+{ -+ return i2c_add_driver(&snd_ubi32_cs4350_driver); -+} -+module_init(snd_ubi32_cs4350_init); -+ -+/* -+ * snd_ubi32_cs4350_exit -+ */ -+static void __exit snd_ubi32_cs4350_exit(void) -+{ -+ i2c_del_driver(&snd_ubi32_cs4350_driver); -+} -+module_exit(snd_ubi32_cs4350_exit); -+ -+/* -+ * Module properties -+ */ -+MODULE_ALIAS("i2c:" DRIVER_NAME); -+MODULE_AUTHOR("Patrick Tjin"); -+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices CS4350"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/sound/ubicom32/ubi32-cs4384.c linux-2.6.30.10-ubi/sound/ubicom32/ubi32-cs4384.c ---- linux-2.6.30.10/sound/ubicom32/ubi32-cs4384.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/ubicom32/ubi32-cs4384.c 2009-12-11 11:45:25.000000000 +0200 -@@ -0,0 +1,996 @@ -+/* -+ * sound/ubicom32/ubi32-cs4384.c -+ * Interface to ubicom32 virtual audio peripheral - using CS4384 DAC -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubi32.h" -+ -+#define DRIVER_NAME "snd-ubi32-cs4384" -+ -+/* -+ * Module properties -+ */ -+static const struct i2c_device_id snd_ubi32_cs4384_id[] = { -+ {"cs4384", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, ubicom32audio_id); -+ -+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ -+ -+/* -+ * Mixer properties -+ */ -+enum { -+ /* -+ * Be careful of changing the order of these IDs, they -+ * are used to index the volume array. -+ */ -+ SND_UBI32_CS4384_FRONT_ID, -+ SND_UBI32_CS4384_SURROUND_ID, -+ SND_UBI32_CS4384_CENTER_ID, -+ SND_UBI32_CS4384_LFE_ID, -+ SND_UBI32_CS4384_REAR_ID, -+ -+ /* -+ * This should be the last ID -+ */ -+ SND_UBI32_CS4384_LAST_ID, -+}; -+static const u8_t snd_ubi32_cs4384_ch_ofs[] = {0, 2, 4, 5, 6}; -+ -+static const DECLARE_TLV_DB_SCALE(snd_ubi32_cs4384_db, -12750, 50, 0); -+ -+#define snd_ubi32_cs4384_info_mute snd_ctl_boolean_stereo_info -+#define snd_ubi32_cs4384_info_mute_mono snd_ctl_boolean_mono_info -+ -+/* -+ * Mixer controls -+ */ -+static int snd_ubi32_cs4384_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -+static int snd_ubi32_cs4384_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_ubi32_cs4384_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_ubi32_cs4384_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_ubi32_cs4384_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+ -+/* -+ * Make sure to update these if the structure below is changed -+ */ -+#define SND_UBI32_MUTE_CTL_START 5 -+#define SND_UBI32_MUTE_CTL_END 9 -+static struct snd_kcontrol_new snd_ubi32_cs4384_controls[] __devinitdata = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "Front Playback Volume", -+ .info = snd_ubi32_cs4384_info_volume, -+ .get = snd_ubi32_cs4384_get_volume, -+ .put = snd_ubi32_cs4384_put_volume, -+ .private_value = SND_UBI32_CS4384_FRONT_ID, -+ .tlv = { -+ .p = snd_ubi32_cs4384_db, -+ }, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "Surround Playback Volume", -+ .info = snd_ubi32_cs4384_info_volume, -+ .get = snd_ubi32_cs4384_get_volume, -+ .put = snd_ubi32_cs4384_put_volume, -+ .private_value = SND_UBI32_CS4384_SURROUND_ID, -+ .tlv = { -+ .p = snd_ubi32_cs4384_db, -+ }, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "Center Playback Volume", -+ .info = snd_ubi32_cs4384_info_volume, -+ .get = snd_ubi32_cs4384_get_volume, -+ .put = snd_ubi32_cs4384_put_volume, -+ .private_value = SND_UBI32_CS4384_CENTER_ID, -+ .tlv = { -+ .p = snd_ubi32_cs4384_db, -+ }, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "LFE Playback Volume", -+ .info = snd_ubi32_cs4384_info_volume, -+ .get = snd_ubi32_cs4384_get_volume, -+ .put = snd_ubi32_cs4384_put_volume, -+ .private_value = SND_UBI32_CS4384_LFE_ID, -+ .tlv = { -+ .p = snd_ubi32_cs4384_db, -+ }, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "Rear Playback Volume", -+ .info = snd_ubi32_cs4384_info_volume, -+ .get = snd_ubi32_cs4384_get_volume, -+ .put = snd_ubi32_cs4384_put_volume, -+ .private_value = SND_UBI32_CS4384_REAR_ID, -+ .tlv = { -+ .p = snd_ubi32_cs4384_db, -+ }, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "Front Playback Switch", -+ .info = snd_ubi32_cs4384_info_mute, -+ .get = snd_ubi32_cs4384_get_mute, -+ .put = snd_ubi32_cs4384_put_mute, -+ .private_value = SND_UBI32_CS4384_FRONT_ID, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "Surround Playback Switch", -+ .info = snd_ubi32_cs4384_info_mute, -+ .get = snd_ubi32_cs4384_get_mute, -+ .put = snd_ubi32_cs4384_put_mute, -+ .private_value = SND_UBI32_CS4384_SURROUND_ID, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "Center Playback Switch", -+ .info = snd_ubi32_cs4384_info_mute_mono, -+ .get = snd_ubi32_cs4384_get_mute, -+ .put = snd_ubi32_cs4384_put_mute, -+ .private_value = SND_UBI32_CS4384_CENTER_ID, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "LFE Playback Switch", -+ .info = snd_ubi32_cs4384_info_mute_mono, -+ .get = snd_ubi32_cs4384_get_mute, -+ .put = snd_ubi32_cs4384_put_mute, -+ .private_value = SND_UBI32_CS4384_LFE_ID, -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, -+ .name = "Rear Playback Switch", -+ .info = snd_ubi32_cs4384_info_mute, -+ .get = snd_ubi32_cs4384_get_mute, -+ .put = snd_ubi32_cs4384_put_mute, -+ .private_value = SND_UBI32_CS4384_REAR_ID, -+ }, -+}; -+ -+/* -+ * Our private data -+ */ -+struct snd_ubi32_cs4384_priv { -+ /* -+ * Array of current volumes -+ * (L, R, SL, SR, C, LFE, RL, RR) -+ */ -+ uint8_t volume[8]; -+ -+ /* -+ * Bitmask of mutes -+ * MSB (RR, RL, LFE, C, SR, SL, R, L) LSB -+ */ -+ uint8_t mute; -+ -+ /* -+ * Array of controls -+ */ -+ struct snd_kcontrol *kctls[ARRAY_SIZE(snd_ubi32_cs4384_controls)]; -+ -+ /* -+ * Lock to protect our card -+ */ -+ spinlock_t lock; -+}; -+ -+/* -+ * snd_ubi32_cs4384_info_volume -+ */ -+static int snd_ubi32_cs4384_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -+{ -+ unsigned int id = (unsigned int)kcontrol->private_value; -+ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ if ((id != SND_UBI32_CS4384_LFE_ID) && -+ (id != SND_UBI32_CS4384_CENTER_ID)) { -+ uinfo->count = 2; -+ } -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = 255; -+ return 0; -+} -+ -+/* -+ * snd_ubi32_cs4384_get_volume -+ */ -+static int snd_ubi32_cs4384_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol); -+ struct snd_ubi32_cs4384_priv *cs4384_priv; -+ unsigned int id = (unsigned int)kcontrol->private_value; -+ int ch = snd_ubi32_cs4384_ch_ofs[id]; -+ unsigned long flags; -+ -+ if (id >= SND_UBI32_CS4384_LAST_ID) { -+ return -EINVAL; -+ } -+ -+ cs4384_priv = snd_ubi32_priv_get_drv(priv); -+ -+ spin_lock_irqsave(&cs4384_priv->lock, flags); -+ -+ ucontrol->value.integer.value[0] = cs4384_priv->volume[ch]; -+ if ((id != SND_UBI32_CS4384_LFE_ID) && -+ (id != SND_UBI32_CS4384_CENTER_ID)) { -+ ch++; -+ ucontrol->value.integer.value[1] = cs4384_priv->volume[ch]; -+ } -+ -+ spin_unlock_irqrestore(&cs4384_priv->lock, flags); -+ -+ return 0; -+} -+ -+/* -+ * snd_ubi32_cs4384_put_volume -+ */ -+static int snd_ubi32_cs4384_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol); -+ struct i2c_client *client = (struct i2c_client *)priv->client; -+ struct snd_ubi32_cs4384_priv *cs4384_priv; -+ unsigned int id = (unsigned int)kcontrol->private_value; -+ int ch = snd_ubi32_cs4384_ch_ofs[id]; -+ unsigned long flags; -+ unsigned char send[3]; -+ int nch; -+ int ret = -EINVAL; -+ -+ if (id >= SND_UBI32_CS4384_LAST_ID) { -+ return -EINVAL; -+ } -+ -+ cs4384_priv = snd_ubi32_priv_get_drv(priv); -+ -+ spin_lock_irqsave(&cs4384_priv->lock, flags); -+ -+ send[0] = 0; -+ switch (id) { -+ case SND_UBI32_CS4384_REAR_ID: -+ send[0] = 0x06; -+ -+ /* -+ * Fall through -+ */ -+ -+ case SND_UBI32_CS4384_SURROUND_ID: -+ send[0] += 0x03; -+ -+ /* -+ * Fall through -+ */ -+ -+ case SND_UBI32_CS4384_FRONT_ID: -+ send[0] += 0x8B; -+ nch = 2; -+ send[1] = 255 - (ucontrol->value.integer.value[0] & 0xFF); -+ send[2] = 255 - (ucontrol->value.integer.value[1] & 0xFF); -+ cs4384_priv->volume[ch++] = send[1]; -+ cs4384_priv->volume[ch] = send[2]; -+ break; -+ -+ case SND_UBI32_CS4384_LFE_ID: -+ send[0] = 0x81; -+ -+ /* -+ * Fall through -+ */ -+ -+ case SND_UBI32_CS4384_CENTER_ID: -+ send[0] += 0x11; -+ nch = 1; -+ send[1] = 255 - (ucontrol->value.integer.value[0] & 0xFF); -+ cs4384_priv->volume[ch] = send[1]; -+ break; -+ -+ default: -+ spin_unlock_irqrestore(&cs4384_priv->lock, flags); -+ goto done; -+ -+ } -+ -+ /* -+ * Send the volume to the chip -+ */ -+ nch++; -+ ret = i2c_master_send(client, send, nch); -+ if (ret != nch) { -+ snd_printk(KERN_ERR "Failed to set volume on CS4384\n"); -+ } -+ -+done: -+ spin_unlock_irqrestore(&cs4384_priv->lock, flags); -+ -+ return ret; -+} -+ -+/* -+ * snd_ubi32_cs4384_get_mute -+ */ -+static int snd_ubi32_cs4384_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol); -+ struct snd_ubi32_cs4384_priv *cs4384_priv; -+ unsigned int id = (unsigned int)kcontrol->private_value; -+ int ch = snd_ubi32_cs4384_ch_ofs[id]; -+ unsigned long flags; -+ -+ if (id >= SND_UBI32_CS4384_LAST_ID) { -+ return -EINVAL; -+ } -+ -+ cs4384_priv = snd_ubi32_priv_get_drv(priv); -+ -+ spin_lock_irqsave(&cs4384_priv->lock, flags); -+ -+ ucontrol->value.integer.value[0] = !(cs4384_priv->mute & (1 << ch)); -+ -+ if ((id != SND_UBI32_CS4384_LFE_ID) && -+ (id != SND_UBI32_CS4384_CENTER_ID)) { -+ ch++; -+ ucontrol->value.integer.value[1] = !(cs4384_priv->mute & (1 << ch)); -+ } -+ -+ spin_unlock_irqrestore(&cs4384_priv->lock, flags); -+ -+ return 0; -+} -+ -+/* -+ * snd_ubi32_cs4384_put_mute -+ */ -+static int snd_ubi32_cs4384_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol); -+ struct i2c_client *client = (struct i2c_client *)priv->client; -+ struct snd_ubi32_cs4384_priv *cs4384_priv; -+ unsigned int id = (unsigned int)kcontrol->private_value; -+ int ch = snd_ubi32_cs4384_ch_ofs[id]; -+ unsigned long flags; -+ unsigned char send[2]; -+ int ret = -EINVAL; -+ -+ if (id >= SND_UBI32_CS4384_LAST_ID) { -+ return -EINVAL; -+ } -+ -+ cs4384_priv = snd_ubi32_priv_get_drv(priv); -+ -+ spin_lock_irqsave(&cs4384_priv->lock, flags); -+ -+ if (ucontrol->value.integer.value[0]) { -+ cs4384_priv->mute &= ~(1 << ch); -+ } else { -+ cs4384_priv->mute |= (1 << ch); -+ } -+ -+ if ((id != SND_UBI32_CS4384_LFE_ID) && (id != SND_UBI32_CS4384_CENTER_ID)) { -+ ch++; -+ if (ucontrol->value.integer.value[1]) { -+ cs4384_priv->mute &= ~(1 << ch); -+ } else { -+ cs4384_priv->mute |= (1 << ch); -+ } -+ } -+ -+ /* -+ * Update the chip's mute reigster -+ */ -+ send[0] = 0x09; -+ send[1] = cs4384_priv->mute; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set mute on CS4384\n"); -+ } -+ -+ spin_unlock_irqrestore(&cs4384_priv->lock, flags); -+ -+ return ret; -+} -+ -+/* -+ * snd_ubi32_cs4384_mixer -+ * Setup the mixer controls -+ */ -+static int __devinit snd_ubi32_cs4384_mixer(struct ubi32_snd_priv *priv) -+{ -+ struct snd_card *card = priv->card; -+ struct snd_ubi32_cs4384_priv *cs4384_priv; -+ int i; -+ -+ cs4384_priv = snd_ubi32_priv_get_drv(priv); -+ for (i = 0; i < ARRAY_SIZE(snd_ubi32_cs4384_controls); i++) { -+ int err; -+ -+ cs4384_priv->kctls[i] = snd_ctl_new1(&snd_ubi32_cs4384_controls[i], priv); -+ err = snd_ctl_add(card, cs4384_priv->kctls[i]); -+ if (err) { -+ snd_printk(KERN_WARNING "Failed to add control %d\n", i); -+ return err; -+ } -+ } -+ return 0; -+} -+ -+/* -+ * snd_ubi32_cs4384_free -+ * Card private data free function -+ */ -+void snd_ubi32_cs4384_free(struct snd_card *card) -+{ -+ struct snd_ubi32_cs4384_priv *cs4384_priv; -+ struct ubi32_snd_priv *ubi32_priv; -+ -+ ubi32_priv = card->private_data; -+ cs4384_priv = snd_ubi32_priv_get_drv(ubi32_priv); -+ if (cs4384_priv) { -+ kfree(cs4384_priv); -+ } -+} -+ -+/* -+ * snd_ubi32_cs4384_setup_mclk -+ */ -+static int snd_ubi32_cs4384_setup_mclk(struct ubi32_cs4384_platform_data *pdata) -+{ -+ struct ubicom32_io_port *ioa = (struct ubicom32_io_port *)RA; -+ struct ubicom32_io_port *ioc = (struct ubicom32_io_port *)RC; -+ struct ubicom32_io_port *iod = (struct ubicom32_io_port *)RD; -+ struct ubicom32_io_port *ioe = (struct ubicom32_io_port *)RE; -+ struct ubicom32_io_port *ioh = (struct ubicom32_io_port *)RH; -+ unsigned int ctl0; -+ unsigned int ctlx; -+ unsigned int div; -+ -+ div = pdata->mclk_entries[0].div; -+ -+ ctl0 = (1 << 13); -+ ctlx = ((div - 1) << 16) | (div / 2); -+ -+ switch (pdata->mclk_src) { -+ case UBI32_CS4384_MCLK_PWM_0: -+ ioc->function |= 2; -+ ioc->ctl0 |= ctl0; -+ ioc->ctl1 = ctlx; -+ if (!ioa->function) { -+ ioa->function = 3; -+ } -+ return 0; -+ -+ case UBI32_CS4384_MCLK_PWM_1: -+ ioc->function |= 2; -+ ioc->ctl0 |= ctl0 << 16; -+ ioc->ctl2 = ctlx; -+ if (!ioe->function) { -+ ioe->function = 3; -+ } -+ return 0; -+ -+ case UBI32_CS4384_MCLK_PWM_2: -+ ioh->ctl0 |= ctl0; -+ ioh->ctl1 = ctlx; -+ if (!iod->function) { -+ iod->function = 3; -+ } -+ return 0; -+ -+ case UBI32_CS4384_MCLK_CLKDIV_1: -+ ioa->gpio_mask &= (1 << 7); -+ ioa->ctl1 &= ~(0x7F << 14); -+ ioa->ctl1 |= ((div - 1) << 14); -+ return 0; -+ -+ case UBI32_CS4384_MCLK_OTHER: -+ return 0; -+ } -+ -+ return 1; -+} -+ -+/* -+ * snd_ubi32_cs4384_set_rate -+ */ -+static int snd_ubi32_cs4384_set_rate(struct ubi32_snd_priv *priv, int rate) -+{ -+ struct ubi32_cs4384_platform_data *cpd = priv->pdata->priv_data; -+ struct ubicom32_io_port *ioa = (struct ubicom32_io_port *)RA; -+ struct ubicom32_io_port *ioc = (struct ubicom32_io_port *)RC; -+ struct ubicom32_io_port *ioh = (struct ubicom32_io_port *)RH; -+ unsigned int ctl; -+ unsigned int div = 0; -+ const u16_t mult[] = {64, 96, 128, 192, 256, 384, 512, 768, 1024}; -+ int i; -+ int j; -+ -+ -+ for (i = 0; i < sizeof(mult) / sizeof(u16_t); i++) { -+ for (j = 0; j < cpd->n_mclk; j++) { -+ if (((unsigned int)rate * (unsigned int)mult[i]) == -+ cpd->mclk_entries[j].rate) { -+ div = cpd->mclk_entries[j].div; -+ break; -+ } -+ } -+ } -+ -+ ctl = ((div - 1) << 16) | (div / 2); -+ -+ switch (cpd->mclk_src) { -+ case UBI32_CS4384_MCLK_PWM_0: -+ ioc->ctl1 = ctl; -+ return 0; -+ -+ case UBI32_CS4384_MCLK_PWM_1: -+ ioc->ctl2 = ctl; -+ return 0; -+ -+ case UBI32_CS4384_MCLK_PWM_2: -+ ioh->ctl1 = ctl; -+ return 0; -+ -+ case UBI32_CS4384_MCLK_CLKDIV_1: -+ ioa->ctl1 &= ~(0x7F << 14); -+ ioa->ctl1 |= ((div - 1) << 14); -+ return 0; -+ -+ case UBI32_CS4384_MCLK_OTHER: -+ return 0; -+ } -+ -+ return 1; -+} -+ -+/* -+ * snd_ubi32_cs4384_set_channels -+ * Mute unused channels -+ */ -+static int snd_ubi32_cs4384_set_channels(struct ubi32_snd_priv *priv, int channels) -+{ -+ struct i2c_client *client = (struct i2c_client *)priv->client; -+ struct snd_ubi32_cs4384_priv *cs4384_priv; -+ unsigned char send[2]; -+ int ret; -+ int i; -+ unsigned long flags; -+ -+ /* -+ * Only support 0, 2, 4, 6, 8 channels -+ */ -+ if ((channels > 8) || (channels & 1)) { -+ return -EINVAL; -+ } -+ -+ cs4384_priv = snd_ubi32_priv_get_drv(priv); -+ spin_lock_irqsave(&cs4384_priv->lock, flags); -+ -+ /* -+ * Address 09h, Mute control -+ */ -+ send[0] = 0x09; -+ send[1] = (unsigned char)(0xFF << channels); -+ -+ ret = i2c_master_send(client, send, 2); -+ -+ spin_unlock_irqrestore(&cs4384_priv->lock, flags); -+ -+ /* -+ * Notify the system that we changed the mutes -+ */ -+ cs4384_priv->mute = (unsigned char)(0xFF << channels); -+ -+ for (i = SND_UBI32_MUTE_CTL_START; i < SND_UBI32_MUTE_CTL_END; i++) { -+ snd_ctl_notify(priv->card, SNDRV_CTL_EVENT_MASK_VALUE, -+ &cs4384_priv->kctls[i]->id); -+ } -+ -+ if (ret != 2) { -+ return -ENXIO; -+ } -+ -+ return 0; -+} -+ -+/* -+ * snd_ubi32_cs4384_dac_init -+ */ -+static int snd_ubi32_cs4384_dac_init(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ int ret; -+ unsigned char send[2]; -+ unsigned char recv[2]; -+ -+ /* -+ * Initialize the CS4384 DAC over the I2C interface -+ */ -+ snd_printk(KERN_INFO "Initializing CS4384 DAC\n"); -+ -+ /* -+ * Register 0x01: device/revid -+ */ -+ send[0] = 0x01; -+ ret = i2c_master_send(client, send, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed 1st attempt to write to CS4384 register 0x01\n"); -+ goto fail; -+ } -+ ret = i2c_master_recv(client, recv, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed initial read of CS4384 registers\n"); -+ goto fail; -+ } -+ snd_printk(KERN_INFO "CS4384 DAC Device/Rev: %08x\n", recv[0]); -+ -+ /* -+ * Register 0x02: Mode Control 1 -+ * Control Port Enable, PCM, All DACs enabled, Power Down -+ */ -+ send[0] = 0x02; -+ send[1] = 0x81; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set CPEN CS4384\n"); -+ goto fail; -+ } -+ -+ /* -+ * Register 0x08: Ramp and Mute -+ * RMP_UP, RMP_DN, PAMUTE, DAMUTE -+ */ -+ send[0] = 0x08; -+ send[1] = 0xBC; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set CPEN CS4384\n"); -+ goto fail; -+ } -+ -+ /* -+ * Register 0x03: PCM Control -+ * I2S DIF[3:0] = 0001, no De-Emphasis, Auto speed mode -+ */ -+ send[0] = 0x03; -+ send[1] = 0x13; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to set CS4384 to I2S mode\n"); -+ goto fail; -+ } -+ -+ /* -+ * Register 0x0B/0x0C: Volume control A1/B1 -+ * Register 0x0E/0x0F: Volume control A2/B2 -+ * Register 0x11/0x12: Volume control A3/B3 -+ * Register 0x14/0x15: Volume control A4/B4 -+ */ -+ send[0] = 0x80 | 0x0B; -+ send[1] = 0x00; -+ send[2] = 0x00; -+ ret = i2c_master_send(client, send, 3); -+ if (ret != 3) { -+ snd_printk(KERN_ERR "Failed to set ch1 volume on CS4384\n"); -+ goto fail; -+ } -+ -+ send[0] = 0x80 | 0x0E; -+ send[1] = 0x00; -+ send[2] = 0x00; -+ ret = i2c_master_send(client, send, 3); -+ if (ret != 3) { -+ snd_printk(KERN_ERR "Failed to set ch2 volume on CS4384\n"); -+ goto fail; -+ } -+ -+ send[0] = 0x80 | 0x11; -+ send[1] = 0x00; -+ send[2] = 0x00; -+ ret = i2c_master_send(client, send, 3); -+ if (ret != 3) { -+ snd_printk(KERN_ERR "Failed to set ch3 volume on CS4384\n"); -+ goto fail; -+ } -+ -+ send[0] = 0x80 | 0x14; -+ send[1] = 0x00; -+ send[2] = 0x00; -+ ret = i2c_master_send(client, send, 3); -+ if (ret != 3) { -+ snd_printk(KERN_ERR "Failed to set ch4 volume on CS4384\n"); -+ goto fail; -+ } -+ -+ /* -+ * Register 09h: Mute control -+ * Mute all (we will unmute channels as needed) -+ */ -+ send[0] = 0x09; -+ send[1] = 0xFF; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to power up CS4384\n"); -+ goto fail; -+ } -+ -+ /* -+ * Register 0x02: Mode Control 1 -+ * Control Port Enable, PCM, All DACs enabled, Power Up -+ */ -+ send[0] = 0x02; -+ send[1] = 0x80; -+ ret = i2c_master_send(client, send, 2); -+ if (ret != 2) { -+ snd_printk(KERN_ERR "Failed to power up CS4384\n"); -+ goto fail; -+ } -+ -+ /* -+ * Make sure the changes took place, this helps verify we are talking to -+ * the correct chip. -+ */ -+ send[0] = 0x80 | 0x03; -+ ret = i2c_master_send(client, send, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed to initiate readback\n"); -+ goto fail; -+ } -+ -+ ret = i2c_master_recv(client, recv, 1); -+ if (ret != 1) { -+ snd_printk(KERN_ERR "Failed second read of CS4384 registers\n"); -+ goto fail; -+ } -+ -+ if (recv[0] != 0x13) { -+ snd_printk(KERN_ERR "Failed to initialize CS4384 DAC\n"); -+ goto fail; -+ } -+ -+ snd_printk(KERN_INFO "CS4384 DAC Initialized\n"); -+ return 0; -+ -+fail: -+ return -ENODEV; -+} -+ -+/* -+ * snd_ubi32_cs4384_i2c_probe -+ */ -+static int snd_ubi32_cs4384_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct snd_card *card; -+ struct ubi32_snd_priv *ubi32_priv; -+ int err, ret; -+ struct platform_device *pdev; -+ struct ubi32_cs4384_platform_data *pdata; -+ struct snd_ubi32_cs4384_priv *cs4384_priv; -+ -+ /* -+ * pdev is audio device -+ */ -+ pdev = client->dev.platform_data; -+ if (!pdev) { -+ return -ENODEV; -+ } -+ -+ /* -+ * pdev->dev.platform_data is ubi32-pcm platform_data -+ */ -+ pdata = audio_device_priv(pdev); -+ if (!pdata) { -+ return -ENODEV; -+ } -+ -+ /* -+ * Initialize the CS4384 DAC -+ */ -+ ret = snd_ubi32_cs4384_dac_init(client, id); -+ if (ret < 0) { -+ /* -+ * Initialization failed. Propagate the error. -+ */ -+ return ret; -+ } -+ -+ if (snd_ubi32_cs4384_setup_mclk(pdata)) { -+ return -EINVAL; -+ } -+ -+ /* -+ * Create a snd_card structure -+ */ -+ card = snd_card_new(index, "Ubi32-CS4384", THIS_MODULE, sizeof(struct ubi32_snd_priv)); -+ if (card == NULL) { -+ return -ENOMEM; -+ } -+ -+ card->private_free = snd_ubi32_cs4384_free; -+ ubi32_priv = card->private_data; -+ -+ /* -+ * Initialize the snd_card's private data structure -+ */ -+ ubi32_priv->card = card; -+ ubi32_priv->client = client; -+ ubi32_priv->set_channels = snd_ubi32_cs4384_set_channels; -+ ubi32_priv->set_rate = snd_ubi32_cs4384_set_rate; -+ -+ /* -+ * CS4384 DAC has a minimum sample rate of 4khz and an -+ * upper limit of 216khz for it's auto-detect. -+ */ -+ ubi32_priv->min_sample_rate = 4000; -+ ubi32_priv->max_sample_rate = 216000; -+ -+ /* -+ * Create our private data (to manage volume, etc) -+ */ -+ cs4384_priv = kzalloc(sizeof(struct snd_ubi32_cs4384_priv), GFP_KERNEL); -+ if (!cs4384_priv) { -+ snd_card_free(card); -+ return -ENOMEM; -+ } -+ snd_ubi32_priv_set_drv(ubi32_priv, cs4384_priv); -+ spin_lock_init(&cs4384_priv->lock); -+ -+ /* -+ * We start off all muted and max volume -+ */ -+ cs4384_priv->mute = 0xFF; -+ memset(cs4384_priv->volume, 0xFF, 8); -+ -+ /* -+ * Create the new PCM instance -+ */ -+ err = snd_ubi32_pcm_probe(ubi32_priv, pdev); -+ if (err < 0) { -+ snd_card_free(card); -+ return err; /* What is err? Need to include correct file */ -+ } -+ -+ strcpy(card->driver, "Ubi32-CS4384"); -+ strcpy(card->shortname, "Ubi32-CS4384"); -+ snprintf(card->longname, sizeof(card->longname), -+ "%s at sendirq=%d.%d recvirq=%d.%d regs=%p", -+ card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx, -+ ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr); -+ -+ snd_card_set_dev(card, &client->dev); -+ -+ /* -+ * Set up the mixer -+ */ -+ snd_ubi32_cs4384_mixer(ubi32_priv); -+ -+ /* -+ * Register the sound card -+ */ -+ if ((err = snd_card_register(card)) != 0) { -+ snd_printk(KERN_INFO "snd_card_register error\n"); -+ } -+ -+ /* -+ * Store card for access from other methods -+ */ -+ i2c_set_clientdata(client, card); -+ -+ return 0; -+} -+ -+/* -+ * snd_ubi32_cs4384_i2c_remove -+ */ -+static int __devexit snd_ubi32_cs4384_i2c_remove(struct i2c_client *client) -+{ -+ struct snd_card *card; -+ struct ubi32_snd_priv *ubi32_priv; -+ -+ card = i2c_get_clientdata(client); -+ -+ ubi32_priv = card->private_data; -+ snd_ubi32_pcm_remove(ubi32_priv); -+ -+ snd_card_free(i2c_get_clientdata(client)); -+ i2c_set_clientdata(client, NULL); -+ -+ return 0; -+} -+ -+/* -+ * I2C driver description -+ */ -+static struct i2c_driver snd_ubi32_cs4384_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ .id_table = snd_ubi32_cs4384_id, -+ .probe = snd_ubi32_cs4384_i2c_probe, -+ .remove = __devexit_p(snd_ubi32_cs4384_i2c_remove), -+}; -+ -+/* -+ * Driver init -+ */ -+static int __init snd_ubi32_cs4384_init(void) -+{ -+ return i2c_add_driver(&snd_ubi32_cs4384_driver); -+} -+module_init(snd_ubi32_cs4384_init); -+ -+/* -+ * snd_ubi32_cs4384_exit -+ */ -+static void __exit snd_ubi32_cs4384_exit(void) -+{ -+ i2c_del_driver(&snd_ubi32_cs4384_driver); -+} -+module_exit(snd_ubi32_cs4384_exit); -+ -+/* -+ * Module properties -+ */ -+MODULE_ALIAS("i2c:" DRIVER_NAME); -+MODULE_AUTHOR("Patrick Tjin"); -+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices CS4384"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/sound/ubicom32/ubi32-generic.c linux-2.6.30.10-ubi/sound/ubicom32/ubi32-generic.c ---- linux-2.6.30.10/sound/ubicom32/ubi32-generic.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/ubicom32/ubi32-generic.c 2009-12-11 11:45:25.000000000 +0200 -@@ -0,0 +1,166 @@ -+/* -+ * sound/ubicom32/ubi32-generic.c -+ * Interface to ubicom32 virtual audio peripheral -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubi32.h" -+ -+#define DRIVER_NAME "snd-ubi32-generic" -+ -+/* -+ * Module properties -+ */ -+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ -+ -+/* -+ * Card private data free function -+ */ -+void snd_ubi32_generic_free(struct snd_card *card) -+{ -+ /* -+ * Free all the fields in the snd_ubi32_priv struct -+ */ -+ // Nothing to free at this time because ubi32_priv just maintains pointers -+} -+ -+/* -+ * Ubicom audio driver probe() method. Args change depending on whether we use -+ * platform_device or i2c_device. -+ */ -+static int snd_ubi32_generic_probe(struct platform_device *dev) -+{ -+ struct snd_card *card; -+ struct ubi32_snd_priv *ubi32_priv; -+ int err; -+ -+ /* -+ * Create a snd_card structure -+ */ -+ card = snd_card_new(index, "Ubi32-Generic", THIS_MODULE, sizeof(struct ubi32_snd_priv)); -+ -+ if (card == NULL) { -+ return -ENOMEM; -+ } -+ -+ card->private_free = snd_ubi32_generic_free; /* Not sure if correct */ -+ ubi32_priv = card->private_data; -+ -+ /* -+ * Initialize the snd_card's private data structure -+ */ -+ ubi32_priv->card = card; -+ -+ /* -+ * Create the new PCM instance -+ */ -+ err = snd_ubi32_pcm_probe(ubi32_priv, dev); -+ if (err < 0) { -+ snd_card_free(card); -+ return err; -+ } -+ -+ strcpy(card->driver, "Ubi32-Generic"); -+ strcpy(card->shortname, "Ubi32-Generic"); -+ snprintf(card->longname, sizeof(card->longname), -+ "%s at sendirq=%d.%d recvirq=%d.%d regs=%p", -+ card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx, -+ ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr); -+ -+ snd_card_set_dev(card, &dev->dev); -+ -+ /* Register the sound card */ -+ if ((err = snd_card_register(card)) != 0) { -+ snd_printk(KERN_INFO "snd_card_register error\n"); -+ } -+ -+ /* Store card for access from other methods */ -+ platform_set_drvdata(dev, card); -+ -+ return 0; -+} -+ -+/* -+ * Ubicom audio driver remove() method -+ */ -+static int __devexit snd_ubi32_generic_remove(struct platform_device *dev) -+{ -+ struct snd_card *card; -+ struct ubi32_snd_priv *ubi32_priv; -+ -+ card = platform_get_drvdata(dev); -+ ubi32_priv = card->private_data; -+ snd_ubi32_pcm_remove(ubi32_priv); -+ -+ snd_card_free(platform_get_drvdata(dev)); -+ platform_set_drvdata(dev, NULL); -+ return 0; -+} -+ -+/* -+ * Platform driver definition -+ */ -+static struct platform_driver snd_ubi32_generic_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ .probe = snd_ubi32_generic_probe, -+ .remove = __devexit_p(snd_ubi32_generic_remove), -+}; -+ -+/* -+ * snd_ubi32_generic_init -+ */ -+static int __init snd_ubi32_generic_init(void) -+{ -+ return platform_driver_register(&snd_ubi32_generic_driver); -+} -+module_init(snd_ubi32_generic_init); -+ -+/* -+ * snd_ubi32_generic_exit -+ */ -+static void __exit snd_ubi32_generic_exit(void) -+{ -+ platform_driver_unregister(&snd_ubi32_generic_driver); -+} -+module_exit(snd_ubi32_generic_exit); -+ -+/* -+ * Module properties -+ */ -+//#if defined(CONFIG_SND_UBI32_AUDIO_I2C) -+//MODULE_ALIAS("i2c:snd-ubi32"); -+//#endif -+MODULE_AUTHOR("Aaron Jow, Patrick Tjin"); -+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/sound/ubicom32/ubi32-generic-capture.c linux-2.6.30.10-ubi/sound/ubicom32/ubi32-generic-capture.c ---- linux-2.6.30.10/sound/ubicom32/ubi32-generic-capture.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/ubicom32/ubi32-generic-capture.c 2009-12-11 11:45:25.000000000 +0200 -@@ -0,0 +1,167 @@ -+/* -+ * sound/ubicom32/ubi32-generic-capture.c -+ * Interface to ubicom32 virtual audio peripheral -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubi32.h" -+ -+#define DRIVER_NAME "snd-ubi32-generic-capture" -+ -+/* -+ * Module properties -+ */ -+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ -+ -+/* -+ * Card private data free function -+ */ -+void snd_ubi32_generic_capture_free(struct snd_card *card) -+{ -+ /* -+ * Free all the fields in the snd_ubi32_priv struct -+ */ -+ // Nothing to free at this time because ubi32_priv just maintains pointers -+} -+ -+/* -+ * Ubicom audio driver probe() method. Args change depending on whether we use -+ * platform_device or i2c_device. -+ */ -+static int snd_ubi32_generic_capture_probe(struct platform_device *dev) -+{ -+ struct snd_card *card; -+ struct ubi32_snd_priv *ubi32_priv; -+ int err; -+ -+ /* -+ * Create a snd_card structure -+ */ -+ card = snd_card_new(index, "Ubi32-Generic-C", THIS_MODULE, sizeof(struct ubi32_snd_priv)); -+ -+ if (card == NULL) { -+ return -ENOMEM; -+ } -+ -+ card->private_free = snd_ubi32_generic_capture_free; /* Not sure if correct */ -+ ubi32_priv = card->private_data; -+ -+ /* -+ * Initialize the snd_card's private data structure -+ */ -+ ubi32_priv->card = card; -+ ubi32_priv->is_capture = 1; -+ -+ /* -+ * Create the new PCM instance -+ */ -+ err = snd_ubi32_pcm_probe(ubi32_priv, dev); -+ if (err < 0) { -+ snd_card_free(card); -+ return err; -+ } -+ -+ strcpy(card->driver, "Ubi32-Generic-C"); -+ strcpy(card->shortname, "Ubi32-Generic-C"); -+ snprintf(card->longname, sizeof(card->longname), -+ "%s at sendirq=%d.%d recvirq=%d.%d regs=%p", -+ card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx, -+ ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr); -+ -+ snd_card_set_dev(card, &dev->dev); -+ -+ /* Register the sound card */ -+ if ((err = snd_card_register(card)) != 0) { -+ snd_printk(KERN_INFO "snd_card_register error\n"); -+ } -+ -+ /* Store card for access from other methods */ -+ platform_set_drvdata(dev, card); -+ -+ return 0; -+} -+ -+/* -+ * Ubicom audio driver remove() method -+ */ -+static int __devexit snd_ubi32_generic_capture_remove(struct platform_device *dev) -+{ -+ struct snd_card *card; -+ struct ubi32_snd_priv *ubi32_priv; -+ -+ card = platform_get_drvdata(dev); -+ ubi32_priv = card->private_data; -+ snd_ubi32_pcm_remove(ubi32_priv); -+ -+ snd_card_free(platform_get_drvdata(dev)); -+ platform_set_drvdata(dev, NULL); -+ return 0; -+} -+ -+/* -+ * Platform driver definition -+ */ -+static struct platform_driver snd_ubi32_generic_capture_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+ .probe = snd_ubi32_generic_capture_probe, -+ .remove = __devexit_p(snd_ubi32_generic_capture_remove), -+}; -+ -+/* -+ * snd_ubi32_generic_capture_init -+ */ -+static int __init snd_ubi32_generic_capture_init(void) -+{ -+ return platform_driver_register(&snd_ubi32_generic_capture_driver); -+} -+module_init(snd_ubi32_generic_capture_init); -+ -+/* -+ * snd_ubi32_generic_capture_exit -+ */ -+static void __exit snd_ubi32_generic_capture_exit(void) -+{ -+ platform_driver_unregister(&snd_ubi32_generic_capture_driver); -+} -+module_exit(snd_ubi32_generic_capture_exit); -+ -+/* -+ * Module properties -+ */ -+//#if defined(CONFIG_SND_UBI32_AUDIO_I2C) -+//MODULE_ALIAS("i2c:snd-ubi32"); -+//#endif -+MODULE_AUTHOR("Patrick Tjin"); -+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices"); -+MODULE_LICENSE("GPL"); -diff -ruN linux-2.6.30.10/sound/ubicom32/ubi32.h linux-2.6.30.10-ubi/sound/ubicom32/ubi32.h ---- linux-2.6.30.10/sound/ubicom32/ubi32.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/ubicom32/ubi32.h 2009-12-11 11:45:25.000000000 +0200 -@@ -0,0 +1,102 @@ -+/* -+ * sound/ubicom32/ubi32.h -+ * Common header file for all ubi32- sound drivers -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ */ -+ -+#ifndef _UBI32_H -+#define _UBI32_H -+ -+#define SND_UBI32_DEBUG 0 // Debug flag -+ -+#include -+#include -+#include -+#include -+ -+struct ubi32_snd_priv; -+ -+typedef int (*set_channels_t)(struct ubi32_snd_priv *priv, int channels); -+typedef int (*set_rate_t)(struct ubi32_snd_priv *priv, int rate); -+ -+struct ubi32_snd_priv { -+ /* -+ * Any variables that are needed locally here but NOT in -+ * the VP itself should go in here. -+ */ -+ struct snd_card *card; -+ struct snd_pcm *pcm; -+ -+ /* -+ * capture (1) or playback (0) -+ */ -+ int is_capture; -+ /* -+ * DAC parameters. These are the parameters for the specific -+ * DAC we are driving. The I2S component can run at a range -+ * of frequencies, but the DAC may be limited. We may want -+ * to make this an array of some sort in the future? -+ * -+ * min/max_sample_rate if set to 0 are ignored. -+ */ -+ int max_sample_rate; -+ int min_sample_rate; -+ -+ /* -+ * The size a period (group) of audio samples. The VP does -+ * not need to know this; each DMA transfer is made to be -+ * one period. -+ */ -+ u32_t period_size; -+ -+ spinlock_t ubi32_lock; -+ -+ struct audio_regs *ar; -+ struct audio_dev_regs *adr; -+ u32 irq_idx; -+ u8 tx_irq; -+ u8 rx_irq; -+ -+ void *client; -+ -+ /* -+ * Operations which the base DAC driver can implement -+ */ -+ set_channels_t set_channels; -+ set_rate_t set_rate; -+ -+ /* -+ * platform data -+ */ -+ struct ubi32pcm_platform_data *pdata; -+ -+ /* -+ * Private driver data (used for DAC driver control, etc) -+ */ -+ void *drvdata; -+}; -+ -+#define snd_ubi32_priv_get_drv(priv) ((priv)->drvdata) -+#define snd_ubi32_priv_set_drv(priv, data) (((priv)->drvdata) = (void *)(data)) -+ -+extern int snd_ubi32_pcm_probe(struct ubi32_snd_priv *ubi32_priv, struct platform_device *pdev); -+extern void snd_ubi32_pcm_remove(struct ubi32_snd_priv *ubi32_priv); -+ -+#endif -diff -ruN linux-2.6.30.10/sound/ubicom32/ubi32-pcm.c linux-2.6.30.10-ubi/sound/ubicom32/ubi32-pcm.c ---- linux-2.6.30.10/sound/ubicom32/ubi32-pcm.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.30.10-ubi/sound/ubicom32/ubi32-pcm.c 2009-12-11 11:45:25.000000000 +0200 -@@ -0,0 +1,711 @@ -+/* -+ * sound/ubicom32/ubi32-pcm.c -+ * Interface to ubicom32 virtual audio peripheral -+ * -+ * (C) Copyright 2009, Ubicom, Inc. -+ * -+ * This file is part of the Ubicom32 Linux Kernel Port. -+ * -+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute -+ * it and/or modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation, either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it -+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied -+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with the Ubicom32 Linux Kernel Port. If not, -+ * see . -+ * -+ * Ubicom32 implementation derived from (with many thanks): -+ * arch/m68knommu -+ * arch/blackfin -+ * arch/parisc -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubi32.h" -+ -+struct ubi32_snd_runtime_data { -+ dma_addr_t dma_buffer; /* Physical address of DMA buffer */ -+ dma_addr_t dma_buffer_end; /* First address beyond end of DMA buffer */ -+ size_t period_size; -+ dma_addr_t period_ptr; /* Physical address of next period */ -+ unsigned int flags; -+}; -+ -+static void snd_ubi32_vp_int_set(struct snd_pcm *pcm) -+{ -+ struct ubi32_snd_priv *ubi32_priv = pcm->private_data; -+ ubi32_priv->ar->int_req |= (1 << ubi32_priv->irq_idx); -+ ubicom32_set_interrupt(ubi32_priv->tx_irq); -+} -+ -+static snd_pcm_uframes_t snd_ubi32_pcm_pointer(struct snd_pcm_substream *substream) -+{ -+ -+ struct ubi32_snd_priv *ubi32_priv = snd_pcm_substream_chip(substream); -+ struct audio_dev_regs *adr = ubi32_priv->adr; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data; -+ -+ dma_addr_t read_pos; -+ -+ snd_pcm_uframes_t frames; -+ if (!adr->primary_os_buffer_ptr) { -+ /* -+ * If primary_os_buffer_ptr is NULL (e.g. right after the HW is started or -+ * when the HW is stopped), then handle this case separately. -+ */ -+ return 0; -+ } -+ -+ read_pos = (dma_addr_t)adr->primary_os_buffer_ptr; -+ frames = bytes_to_frames(runtime, read_pos - ubi32_rd->dma_buffer); -+ if (frames == runtime->buffer_size) { -+ frames = 0; -+ } -+ return frames; -+} -+ -+/* -+ * Audio trigger -+ */ -+static int snd_ubi32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data; -+ struct audio_dev_regs *adr = ubi32_priv->adr; -+ struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data; -+ int ret = 0; -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "snd_ubi32_pcm_trigger cmd=%d=", cmd); -+#endif -+ -+ if (adr->command != AUDIO_CMD_NONE) { -+ snd_printk(KERN_WARNING "Can't send command to audio device at this time\n"); -+ // Set a timer to call this function back later. How to do this? -+ return 0; -+ } -+ -+ /* -+ * Set interrupt flag to indicate that we interrupted audio device -+ * to send a command -+ */ -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "START\n"); -+#endif -+ /* -+ * Ready the DMA transfer -+ */ -+ ubi32_rd->period_ptr = ubi32_rd->dma_buffer; -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "trigger period_ptr=%lx\n", (unsigned long)ubi32_rd->period_ptr); -+#endif -+ adr->dma_xfer_requests[0].ptr = (void *)ubi32_rd->period_ptr; -+ adr->dma_xfer_requests[0].ctr = ubi32_rd->period_size; -+ adr->dma_xfer_requests[0].active = 1; -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "xfer_request 0 ptr=0x%x ctr=%u\n", ubi32_rd->period_ptr, ubi32_rd->period_size); -+#endif -+ -+ ubi32_rd->period_ptr += ubi32_rd->period_size; -+ adr->dma_xfer_requests[1].ptr = (void *)ubi32_rd->period_ptr; -+ adr->dma_xfer_requests[1].ctr = ubi32_rd->period_size; -+ adr->dma_xfer_requests[1].active = 1; -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "xfer_request 1 ptr=0x%x ctr=%u\n", ubi32_rd->period_ptr, ubi32_rd->period_size); -+#endif -+ -+ /* -+ * Tell the VP that we want to begin playback by filling in the -+ * command field and then interrupting the audio VP -+ */ -+ adr->int_flags |= AUDIO_INT_FLAG_COMMAND; -+ adr->command = AUDIO_CMD_START; -+ snd_ubi32_vp_int_set(substream->pcm); -+ break; -+ -+ case SNDRV_PCM_TRIGGER_STOP: -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "STOP\n"); -+#endif -+ -+ /* -+ * Tell the VP that we want to stop playback by filling in the -+ * command field and then interrupting the audio VP -+ */ -+ adr->int_flags |= AUDIO_INT_FLAG_COMMAND; -+ adr->command = AUDIO_CMD_STOP; -+ snd_ubi32_vp_int_set(substream->pcm); -+ break; -+ -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "PAUSE_PUSH\n"); -+#endif -+ -+ /* -+ * Tell the VP that we want to pause playback by filling in the -+ * command field and then interrupting the audio VP -+ */ -+ adr->int_flags |= AUDIO_INT_FLAG_COMMAND; -+ adr->command = AUDIO_CMD_PAUSE; -+ snd_ubi32_vp_int_set(substream->pcm); -+ break; -+ -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "PAUSE_RELEASE\n"); -+#endif -+ /* -+ * Tell the VP that we want to resume paused playback by filling -+ * in the command field and then interrupting the audio VP -+ */ -+ adr->int_flags |= AUDIO_INT_FLAG_COMMAND; -+ adr->command = AUDIO_CMD_RESUME; -+ snd_ubi32_vp_int_set(substream->pcm); -+ break; -+ -+ default: -+ snd_printk(KERN_WARNING "Unhandled trigger\n"); -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+/* -+ * Prepare to transfer an audio stream to the codec -+ */ -+static int snd_ubi32_pcm_prepare(struct snd_pcm_substream *substream) -+{ -+ /* -+ * Configure registers and setup the runtime instance for DMA transfers -+ */ -+ struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data; -+ struct audio_dev_regs *adr = ubi32_priv->adr; -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "snd_ubi32_pcm_prepare: sending STOP command to audio device\n"); -+#endif -+ -+ /* -+ * Make sure the audio device is stopped -+ */ -+ -+ /* -+ * Set interrupt flag to indicate that we interrupted audio device -+ * to send a command -+ */ -+ adr->int_flags |= AUDIO_INT_FLAG_COMMAND; -+ adr->command = AUDIO_CMD_STOP; -+ snd_ubi32_vp_int_set(substream->pcm); -+ -+ return 0; -+} -+ -+/* -+ * Allocate DMA buffers from preallocated memory. -+ * Preallocation was done in snd_ubi32_pcm_new() -+ */ -+static int snd_ubi32_pcm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *hw_params) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data; -+ struct audio_dev_regs *adr = ubi32_priv->adr; -+ struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data; -+ -+ /* -+ * Use pre-allocated memory from ubi32_snd_pcm_new() to satisfy -+ * this memory request. -+ */ -+ int ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); -+ if (ret < 0) { -+ return ret; -+ } -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "snd_ubi32_pcm_hw_params\n"); -+#endif -+ -+ if (!(adr->channel_mask & (1 << params_channels(hw_params)))) { -+ snd_printk(KERN_INFO "snd_ubi32_pcm_hw_params unsupported number of channels %d mask %08x\n", params_channels(hw_params), adr->channel_mask); -+ return -EINVAL; -+ } -+ -+ if (ubi32_priv->set_channels) { -+ int ret = ubi32_priv->set_channels(ubi32_priv, params_channels(hw_params)); -+ if (ret) { -+ snd_printk(KERN_WARNING "Unable to set channels to %d, ret=%d\n", params_channels(hw_params), ret); -+ return ret; -+ } -+ } -+ -+ if (ubi32_priv->set_rate) { -+ int ret = ubi32_priv->set_rate(ubi32_priv, params_rate(hw_params)); -+ if (ret) { -+ snd_printk(KERN_WARNING "Unable to set rate to %d, ret=%d\n", params_rate(hw_params), ret); -+ return ret; -+ } -+ } -+ -+ if (ubi32_priv->pdata->set_rate) { -+ int ret = ubi32_priv->pdata->set_rate(ubi32_priv->pdata->appdata, params_rate(hw_params)); -+ if (ret) { -+ snd_printk(KERN_WARNING "Unable to set rate to %d, ret=%d\n", params_rate(hw_params), ret); -+ return ret; -+ } -+ } -+ -+ if (adr->command != AUDIO_CMD_NONE) { -+ snd_printk(KERN_WARNING "snd_ubi32_pcm_hw_params: tio busy\n"); -+ return -EAGAIN; -+ } -+ -+ if (params_format(hw_params) == SNDRV_PCM_FORMAT_S16_LE) { -+ adr->flags |= CMD_START_FLAG_LE; -+ } else { -+ adr->flags &= ~CMD_START_FLAG_LE; -+ } -+ adr->channels = params_channels(hw_params); -+ adr->sample_rate = params_rate(hw_params); -+ adr->command = AUDIO_CMD_SETUP; -+ adr->int_flags |= AUDIO_INT_FLAG_COMMAND; -+ snd_ubi32_vp_int_set(substream->pcm); -+ -+ /* -+ * Wait for the command to complete -+ */ -+ while (adr->command != AUDIO_CMD_NONE) { -+ udelay(1); -+ } -+ -+ /* -+ * Put the DMA info into the DMA descriptor that we will -+ * use to do transfers to our audio VP "hardware" -+ */ -+ -+ /* -+ * Mark both DMA transfers as not ready/inactive -+ */ -+ adr->dma_xfer_requests[0].active = 0; -+ adr->dma_xfer_requests[1].active = 0; -+ -+ /* -+ * Put the location of the buffer into the runtime data instance -+ */ -+ ubi32_rd->dma_buffer = (dma_addr_t)runtime->dma_area; -+ ubi32_rd->dma_buffer_end = (dma_addr_t)(runtime->dma_area + runtime->dma_bytes); -+ -+ /* -+ * Get the period size -+ */ -+ ubi32_rd->period_size = params_period_bytes(hw_params); -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "DMA for ubi32 audio initialized dma_area=0x%x dma_bytes=%d, period_size=%d\n", (unsigned int)runtime->dma_area, (unsigned int)runtime->dma_bytes, ubi32_rd->period_size); -+ snd_printk(KERN_INFO "Private buffer ubi32_rd: dma_buffer=0x%x dma_buffer_end=0x%x ret=%d\n", ubi32_rd->dma_buffer, ubi32_rd->dma_buffer_end, ret); -+#endif -+ -+ return ret; -+} -+ -+/* -+ * This is the reverse of snd_ubi32_pcm_hw_params -+ */ -+static int snd_ubi32_pcm_hw_free(struct snd_pcm_substream *substream) -+{ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "snd_ubi32_pcm_hw_free\n"); -+#endif -+ return snd_pcm_lib_free_pages(substream); -+} -+ -+/* -+ * Audio virtual peripheral capabilities (capture and playback are identical) -+ */ -+static struct snd_pcm_hardware snd_ubi32_pcm_hw = -+{ -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | -+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), -+ .buffer_bytes_max = (64*1024), -+ .period_bytes_min = 64, -+ .period_bytes_max = 8184,//8184,//8176, -+ .periods_min = 2, -+ .periods_max = 255, -+ .fifo_size = 0, // THIS IS IGNORED BY ALSA -+}; -+ -+/* -+ * We fill this in later -+ */ -+static struct snd_pcm_hw_constraint_list ubi32_pcm_rates; -+ -+/* -+ * snd_ubi32_pcm_close -+ */ -+static int snd_ubi32_pcm_close(struct snd_pcm_substream *substream) -+{ -+ /* Disable codec, stop DMA, free private data structures */ -+ //struct ubi32_snd_priv *ubi32_priv = snd_pcm_substream_chip(substream); -+ struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data; -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "snd_ubi32_pcm_close\n"); -+#endif -+ -+ substream->runtime->private_data = NULL; -+ -+ kfree(ubi32_rd); -+ -+ return 0; -+} -+ -+/* -+ * snd_ubi32_pcm_open -+ */ -+static int snd_ubi32_pcm_open(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct ubi32_snd_runtime_data *ubi32_rd; -+ int ret = 0; -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "ubi32 pcm open\n"); -+#endif -+ -+ /* Associate capabilities with component */ -+ runtime->hw = snd_ubi32_pcm_hw; -+ -+ /* -+ * Inform ALSA about constraints of the audio device -+ */ -+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &ubi32_pcm_rates); -+ if (ret < 0) { -+ snd_printk(KERN_INFO "invalid rate\n"); -+ goto out; -+ } -+ -+ /* Force the buffer size to be an integer multiple of period size */ -+ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); -+ if (ret < 0) { -+ snd_printk(KERN_INFO "invalid period\n"); -+ goto out; -+ } -+ /* Initialize structures/registers */ -+ ubi32_rd = kzalloc(sizeof(struct ubi32_snd_runtime_data), GFP_KERNEL); -+ if (ubi32_rd == NULL) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ runtime->private_data = ubi32_rd; -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "snd_ubi32_pcm_open returned 0\n"); -+#endif -+ -+ return 0; -+out: -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "snd_ubi32_pcm_open returned %d\n", ret); -+#endif -+ -+ return ret; -+} -+ -+static struct snd_pcm_ops snd_ubi32_pcm_ops = { -+ .open = snd_ubi32_pcm_open, /* Open */ -+ .close = snd_ubi32_pcm_close, /* Close */ -+ .ioctl = snd_pcm_lib_ioctl, /* Generic IOCTL handler */ -+ .hw_params = snd_ubi32_pcm_hw_params, /* Hardware parameters/capabilities */ -+ .hw_free = snd_ubi32_pcm_hw_free, /* Free function for hw_params */ -+ .prepare = snd_ubi32_pcm_prepare, -+ .trigger = snd_ubi32_pcm_trigger, -+ .pointer = snd_ubi32_pcm_pointer, -+}; -+ -+/* -+ * Interrupt handler that gets called when the audio device -+ * interrupts Linux -+ */ -+static irqreturn_t snd_ubi32_pcm_interrupt(int irq, void *appdata) -+{ -+ struct snd_pcm *pcm = (struct snd_pcm *)appdata; -+ struct ubi32_snd_priv *ubi32_priv = pcm->private_data; -+ struct audio_dev_regs *adr = ubi32_priv->adr; -+ struct snd_pcm_substream *substream; -+ struct ubi32_snd_runtime_data *ubi32_rd; -+ int dma_to_fill = 0; -+ -+ /* -+ * Check to see if the interrupt is for us -+ */ -+ if (!(ubi32_priv->ar->int_status & (1 << ubi32_priv->irq_idx))) { -+ return IRQ_NONE; -+ } -+ -+ /* -+ * Clear the interrupt -+ */ -+ ubi32_priv->ar->int_status &= ~(1 << ubi32_priv->irq_idx); -+ -+ /* -+ * We only have one stream since we don't mix. Therefore -+ * we don't need to search through substreams. -+ */ -+ if (ubi32_priv->is_capture) { -+ substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; -+ } else { -+ substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; -+ } -+ -+ if (!substream->runtime) { -+ snd_printk(KERN_WARNING "No runtime data\n"); -+ return IRQ_NONE; -+ } -+ -+ ubi32_rd = substream->runtime->private_data; -+ -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "Ubi32 ALSA interrupt\n"); -+#endif -+ -+ if (ubi32_rd == NULL) { -+ snd_printk(KERN_WARNING "No private data\n"); -+ return IRQ_NONE; -+ } -+ -+ // Check interrupt cause -+ if (0) { -+ // Handle the underflow case -+ } else if ((adr->status & AUDIO_STATUS_PLAY_DMA0_REQUEST) || -+ (adr->status & AUDIO_STATUS_PLAY_DMA1_REQUEST)) { -+ if (adr->status & AUDIO_STATUS_PLAY_DMA0_REQUEST) { -+ dma_to_fill = 0; -+ adr->status &= ~AUDIO_STATUS_PLAY_DMA0_REQUEST; -+ } else if (adr->status & AUDIO_STATUS_PLAY_DMA1_REQUEST) { -+ dma_to_fill = 1; -+ adr->status &= ~AUDIO_STATUS_PLAY_DMA1_REQUEST; -+ } -+ ubi32_rd->period_ptr += ubi32_rd->period_size; -+ if (ubi32_rd->period_ptr >= ubi32_rd->dma_buffer_end) { -+ ubi32_rd->period_ptr = ubi32_rd->dma_buffer; -+ } -+ adr->dma_xfer_requests[dma_to_fill].ptr = (void *)ubi32_rd->period_ptr; -+ adr->dma_xfer_requests[dma_to_fill].ctr = ubi32_rd->period_size; -+ adr->dma_xfer_requests[dma_to_fill].active = 1; -+#ifdef CONFIG_SND_DEBUG -+ snd_printk(KERN_INFO "xfer_request %d ptr=0x%x ctr=%u\n", dma_to_fill, ubi32_rd->period_ptr, ubi32_rd->period_size); -+#endif -+ adr->int_flags |= AUDIO_INT_FLAG_MORE_SAMPLES; -+ snd_ubi32_vp_int_set(substream->pcm); -+ } -+ // If we are interrupted by the VP, that means we completed -+ // processing one period of audio. We need to inform the upper -+ // layers of ALSA of this. -+ snd_pcm_period_elapsed(substream); -+ -+ return IRQ_HANDLED; -+} -+ -+void __devexit snd_ubi32_pcm_remove(struct ubi32_snd_priv *ubi32_priv) -+{ -+ struct snd_pcm *pcm = ubi32_priv->pcm; -+ free_irq(ubi32_priv->rx_irq, pcm); -+} -+ -+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 -+#error "Change this table to match pcm.h" -+#endif -+static unsigned int rates[] __initdata = {5512, 8000, 11025, 16000, 22050, -+ 32000, 44100, 48000, 64000, 88200, -+ 96000, 176400, 192000}; -+ -+/* -+ * snd_ubi32_pcm_probe -+ */ -+int __devinit snd_ubi32_pcm_probe(struct ubi32_snd_priv *ubi32_priv, struct platform_device *pdev) -+{ -+ struct snd_pcm *pcm; -+ int ret, err; -+ int i; -+ int j; -+ int nrates; -+ unsigned int rate_max = 0; -+ unsigned int rate_min = 0xFFFFFFFF; -+ unsigned int rate_mask = 0; -+ struct audio_dev_regs *adr; -+ struct resource *res_adr; -+ struct resource *res_irq_tx; -+ struct resource *res_irq_rx; -+ struct ubi32pcm_platform_data *pdata; -+ -+ pdata = pdev->dev.platform_data; -+ if (!pdata) { -+ return -ENODEV; -+ } -+ -+ /* -+ * Get our resources, adr is the hardware driver base address -+ * and the tx and rx irqs are used to communicate with the -+ * hardware driver. -+ */ -+ res_adr = platform_get_resource(pdev, IORESOURCE_MEM, AUDIO_MEM_RESOURCE); -+ res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, AUDIO_TX_IRQ_RESOURCE); -+ res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, AUDIO_RX_IRQ_RESOURCE); -+ if (!res_adr || !res_irq_tx || !res_irq_rx) { -+ snd_printk(KERN_WARNING "Could not get resources"); -+ return -ENODEV; -+ } -+ -+ ubi32_priv->ar = (struct audio_regs *)res_adr->start; -+ ubi32_priv->tx_irq = res_irq_tx->start; -+ ubi32_priv->rx_irq = res_irq_rx->start; -+ ubi32_priv->irq_idx = pdata->inst_num; -+ ubi32_priv->adr = &(ubi32_priv->ar->adr[pdata->inst_num]); -+ -+ /* -+ * Check the version -+ */ -+ adr = ubi32_priv->adr; -+ if (adr->version != AUDIO_DEV_REGS_VERSION) { -+ snd_printk(KERN_WARNING "This audio_dev_reg is not compatible with this driver\n"); -+ return -ENODEV; -+ } -+ -+ /* -+ * Find out the standard rates, also find max and min rates -+ */ -+ for (i = 0; i < ARRAY_SIZE(rates); i++) { -+ int found = 0; -+ for (j = 0; j < adr->n_sample_rates; j++) { -+ if (rates[i] == adr->sample_rates[j]) { -+ /* -+ * Check to see if it is supported by the dac -+ */ -+ if ((rates[i] >= ubi32_priv->min_sample_rate) && -+ (!ubi32_priv->max_sample_rate || -+ (ubi32_priv->max_sample_rate && (rates[i] <= ubi32_priv->max_sample_rate)))) { -+ found = 1; -+ rate_mask |= (1 << i); -+ nrates++; -+ if (rates[i] < rate_min) { -+ rate_min = rates[i]; -+ } -+ if (rates[i] > rate_max) { -+ rate_max = rates[i]; -+ } -+ break; -+ } -+ } -+ } -+ if (!found) { -+ rate_mask |= SNDRV_PCM_RATE_KNOT; -+ } -+ } -+ -+ snd_ubi32_pcm_hw.rates = rate_mask; -+ snd_ubi32_pcm_hw.rate_min = rate_min; -+ snd_ubi32_pcm_hw.rate_max = rate_max; -+ ubi32_pcm_rates.count = adr->n_sample_rates; -+ ubi32_pcm_rates.list = (unsigned int *)adr->sample_rates; -+ ubi32_pcm_rates.mask = 0; -+ -+ for (i = 0; i < 32; i++) { -+ if (adr->channel_mask & (1 << i)) { -+ if (!snd_ubi32_pcm_hw.channels_min) { -+ snd_ubi32_pcm_hw.channels_min = i; -+ } -+ snd_ubi32_pcm_hw.channels_max = i; -+ } -+ } -+ snd_printk(KERN_INFO "Ubi32PCM: channels_min:%u channels_max:%u\n", -+ snd_ubi32_pcm_hw.channels_min, -+ snd_ubi32_pcm_hw.channels_max); -+ -+ if (adr->caps & AUDIONODE_CAP_BE) { -+ snd_ubi32_pcm_hw.formats |= SNDRV_PCM_FMTBIT_S16_BE; -+ } -+ if (adr->caps & AUDIONODE_CAP_LE) { -+ snd_ubi32_pcm_hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; -+ } -+ -+ snd_printk(KERN_INFO "Ubi32PCM: rates:%08x min:%u max:%u count:%d fmts:%016llx (%s)\n", -+ snd_ubi32_pcm_hw.rates, -+ snd_ubi32_pcm_hw.rate_min, -+ snd_ubi32_pcm_hw.rate_max, -+ ubi32_pcm_rates.count, -+ snd_ubi32_pcm_hw.formats, -+ ubi32_priv->is_capture ? "capture" : "playback"); -+ -+ if (ubi32_priv->is_capture) { -+ ret = snd_pcm_new(ubi32_priv->card, "Ubi32 PCM", 0, 0, 1, &pcm); -+ } else { -+ ret = snd_pcm_new(ubi32_priv->card, "Ubi32 PCM", 0, 1, 0, &pcm); -+ } -+ -+ if (ret < 0) { -+ return ret; -+ } -+ -+ pcm->private_data = ubi32_priv; -+ ubi32_priv->pcm = pcm; -+ ubi32_priv->pdata = pdata; -+ -+ pcm->info_flags = 0; -+ -+ strcpy(pcm->name, "Ubi32-PCM"); -+ -+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, -+ snd_dma_continuous_data(GFP_KERNEL), -+ 45*1024, 64*1024); -+ -+ if (ubi32_priv->is_capture) { -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ubi32_pcm_ops); -+ } else { -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ubi32_pcm_ops); -+ } -+ -+ /* -+ * Start up the audio device -+ */ -+ adr->int_flags |= AUDIO_INT_FLAG_COMMAND; -+ adr->command = AUDIO_CMD_ENABLE; -+ snd_ubi32_vp_int_set(pcm); -+ -+ /* -+ * Request IRQ -+ */ -+ err = request_irq(ubi32_priv->rx_irq, snd_ubi32_pcm_interrupt, IRQF_SHARED | IRQF_DISABLED, pcm->name, pcm); -+ if (err) { -+ snd_printk(KERN_WARNING "request_irq failed: irq=%d err=%d\n", ubi32_priv->rx_irq, err); -+ return -ENODEV; -+ } -+ -+ return ret; -+ -+} diff --git a/target/linux/ubicom32/patches-2.6.32/100-ubicom32_support.patch b/target/linux/ubicom32/patches-2.6.32/100-ubicom32_support.patch new file mode 100644 index 000000000..e16ec7dda --- /dev/null +++ b/target/linux/ubicom32/patches-2.6.32/100-ubicom32_support.patch @@ -0,0 +1,1725 @@ +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -186,3 +186,16 @@ config HW_RANDOM_MXC_RNGA + module will be called mxc-rnga. + + If unsure, say Y. ++ ++config HW_RANDOM_UBICOM32 ++ tristate "Ubicom32 HW Random Number Generator support" ++ depends on HW_RANDOM && UBICOM32 ++ default HW_RANDOM ++ ---help--- ++ This driver provides kernel-side support for the Random Number ++ Generator hardware found on Ubicom32 processors. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called pasemi-rng. ++ ++ If unsure, say Y. +--- a/drivers/char/hw_random/Makefile ++++ b/drivers/char/hw_random/Makefile +@@ -18,3 +18,4 @@ obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio + obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o + obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o + obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o ++obj-$(CONFIG_HW_RANDOM_UBICOM32) += ubicom32-rng.o +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -61,6 +61,40 @@ config CRYPTO_DEV_GEODE + To compile this driver as a module, choose M here: the module + will be called geode-aes. + ++config CRYPTO_UBICOM32 ++ bool "Ubicom32 Security Module" ++ depends on UBICOM32 ++ help ++ This is the ubicom32 hardware acceleration common code. ++ ++config CRYPTO_AES_UBICOM32 ++ tristate "Ubicom32 AES implementation" ++ depends on CRYPTO_UBICOM32 ++ select CRYPTO_ALGAPI ++ help ++ This is the ubicom32 hardware AES implementation. ++ ++config CRYPTO_DES_UBICOM32 ++ tristate "Ubicom32 DES implementation" ++ depends on CRYPTO_UBICOM32 ++ select CRYPTO_ALGAPI ++ help ++ This is the ubicom32 hardware DES and 3DES implementation. ++ ++config CRYPTO_SHA1_UBICOM32 ++ tristate "Ubicom32 SHA1 implementation" ++ depends on CRYPTO_UBICOM32 ++ select CRYPTO_ALGAPI ++ help ++ This is the ubicom32 hardware SHA1 implementation. ++ ++config CRYPTO_MD5_UBICOM32 ++ tristate "Ubicom32 MD5 implementation" ++ depends on CRYPTO_UBICOM32 ++ select CRYPTO_ALGAPI ++ help ++ This is the ubicom32 hardware MD5 implementation. ++ + config ZCRYPT + tristate "Support for PCI-attached cryptographic adapters" + depends on S390 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -382,3 +382,10 @@ config MMC_VIA_SDMMC + If you have a controller with this interface, say Y or M here. + + If unsure, say N. ++ ++config MMC_UBICOM32 ++ tristate "Ubicom32 MMC/SD host controller" ++ depends on UBICOM32 ++ help ++ This provides support for the SD/MMC hardware found on Ubicom32 ++ IP7K processors +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -35,6 +35,7 @@ obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o + obj-$(CONFIG_MMC_CB710) += cb710-mmc.o + obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o + obj-$(CONFIG_GPIOMMC) += gpiommc.o ++obj-$(CONFIG_MMC_UBICOM32) += ubicom32sd.o + + ifeq ($(CONFIG_CB710_DEBUG),y) + CFLAGS-cb710-mmc += -DDEBUG +--- a/drivers/mtd/devices/Kconfig ++++ b/drivers/mtd/devices/Kconfig +@@ -114,6 +114,31 @@ config MTD_SST25L + Set up your spi devices with the right board-specific platform data, + if you want to specify device partitioning. + ++config MTD_UBI32_NAND_SPI_ER ++ tristate "UBI32_NAND SPI-ER support" ++ help ++ This driver supports the Micron MT29F1G01 SPI-ER NAND flash chip ++ using the built in flash controller on the Ubicom32 architecture. ++ Partial page writes are not supported by this driver. ++ ++config MTD_NAND_SPI_ER ++ tristate "NAND SPI-ER support" ++ help ++ This driver supports the Micron MT29F1G01 SPI-ER NAND flash chip ++ using a generic SPI bus. Partial page writes are supported ++ by this driver. ++ ++config MTD_UBI32_M25P80 ++ tristate "Ubicom processor support for most SPI Flash chips (AT26DF, M25P, W25X, ...)" ++ depends on UBICOM32 ++ default y ++ help ++ This enables access to most modern SPI flash chips, used for ++ program and data storage. Series supported include Atmel AT26DF, ++ Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X. Other chips ++ are supported as well. See the driver source for the current list, ++ or to add other chips. ++ + config MTD_SLRAM + tristate "Uncached system RAM" + help +--- a/drivers/mtd/devices/Makefile ++++ b/drivers/mtd/devices/Makefile +@@ -17,3 +17,6 @@ obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd + obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o + obj-$(CONFIG_MTD_M25P80) += m25p80.o + obj-$(CONFIG_MTD_SST25L) += sst25l.o ++obj-$(CONFIG_MTD_UBI32_M25P80) += ubi32-m25p80.o ++obj-$(CONFIG_MTD_NAND_SPI_ER) += nand-spi-er.o ++obj-$(CONFIG_MTD_UBI32_NAND_SPI_ER) += ubi32-nand-spi-er.o +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -2608,6 +2608,19 @@ config S6GMAC + + source "drivers/net/stmmac/Kconfig" + ++config UBICOM32_GMAC ++ tristate "Ubicom Gigabit Ethernet support" ++ depends on UBICOM32 ++ help ++ Gigabit Ethernet support for ubicom32 processors ++ ++config UBICOM32_OCM_FOR_SKB ++ bool "USE OCM for SKB (EXPERIMENTAL)" ++ depends on UBICOM32_GMAC ++ default n ++ help ++ Allocate skb from OCM for Ethernet Receive when possible ++ + endif # NETDEV_1000 + + # +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -286,3 +286,5 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o + obj-$(CONFIG_SFC) += sfc/ + + obj-$(CONFIG_WIMAX) += wimax/ ++ ++obj-$(CONFIG_UBICOM32_GMAC) += ubi32-eth.o +--- a/drivers/net/usb/asix.c ++++ b/drivers/net/usb/asix.c +@@ -319,14 +319,33 @@ static int asix_rx_fixup(struct usbnet * + /* get the packet length */ + size = (u16) (header & 0x0000ffff); + +- if ((skb->len) - ((size + 1) & 0xfffe) == 0) ++ if ((skb->len) - ((size + 1) & 0xfffe) == 0) { ++#ifndef HAVE_EFFICIENT_UNALIGNED_ACCESS ++ if (((u32)packet & 0x02) == 0) { ++ memmove(packet - 2, packet, size); ++ skb->data -= 2; ++ skb->tail -= 2; ++ } ++#endif + return 2; ++ } ++ + if (size > ETH_FRAME_LEN) { + deverr(dev,"asix_rx_fixup() Bad RX Length %d", size); + return 0; + } + ax_skb = skb_clone(skb, GFP_ATOMIC); + if (ax_skb) { ++#ifndef HAVE_EFFICIENT_UNALIGNED_ACCESS ++ if (((u32)packet & 0x02) == 0) { ++ memmove(packet - 2, packet, size); ++ ax_skb->data = packet - 2; ++ } else { ++ ax_skb->data = packet; ++ } ++#else ++ ax_skb->data = packet; ++#endif + ax_skb->len = size; + ax_skb->data = packet; + skb_set_tail_pointer(ax_skb, size); +@@ -1125,13 +1144,19 @@ static int ax88178_link_reset(struct usb + mode = AX88178_MEDIUM_DEFAULT; + + if (ecmd.speed == SPEED_1000) ++#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS + mode |= AX_MEDIUM_GM; ++#else ++ mode |= AX_MEDIUM_GM | AX_MEDIUM_ENCK; ++#endif + else if (ecmd.speed == SPEED_100) + mode |= AX_MEDIUM_PS; + else + mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); + ++#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS + mode |= AX_MEDIUM_ENCK; ++#endif + + if (ecmd.duplex == DUPLEX_FULL) + mode |= AX_MEDIUM_FD; +--- a/drivers/oprofile/cpu_buffer.c ++++ b/drivers/oprofile/cpu_buffer.c +@@ -327,10 +327,10 @@ static inline void oprofile_end_trace(st + } + + static inline void +-__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, +- unsigned long event, int is_kernel) ++__oprofile_add_ext_sample_cpu(unsigned long pc, struct pt_regs * const regs, ++ unsigned long event, int is_kernel, int cpu) + { +- struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); ++ struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); + unsigned long backtrace = oprofile_backtrace_depth; + + /* +@@ -352,7 +352,8 @@ __oprofile_add_ext_sample(unsigned long + void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, + unsigned long event, int is_kernel) + { +- __oprofile_add_ext_sample(pc, regs, event, is_kernel); ++ __oprofile_add_ext_sample_cpu(pc, regs, event, ++ is_kernel, smp_processor_id()); + } + + void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) +@@ -360,7 +361,8 @@ void oprofile_add_sample(struct pt_regs + int is_kernel = !user_mode(regs); + unsigned long pc = profile_pc(regs); + +- __oprofile_add_ext_sample(pc, regs, event, is_kernel); ++ __oprofile_add_ext_sample_cpu(pc, regs, event, ++ is_kernel, smp_processor_id()); + } + + /* +--- a/drivers/pci/Makefile ++++ b/drivers/pci/Makefile +@@ -47,8 +47,8 @@ obj-$(CONFIG_PPC) += setup-bus.o + obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o + obj-$(CONFIG_X86_VISWS) += setup-irq.o + obj-$(CONFIG_MN10300) += setup-bus.o ++obj-$(CONFIG_UBICOM32) += setup-bus.o setup-irq.o + +-# + # ACPI Related PCI FW Functions + # + obj-$(CONFIG_ACPI) += pci-acpi.o +--- a/drivers/serial/Kconfig ++++ b/drivers/serial/Kconfig +@@ -879,6 +879,57 @@ config SERIAL_UARTLITE_CONSOLE + console (the system console is the device which receives all kernel + messages and warnings and which allows logins in single user mode). + ++config SERIAL_UBI32_UARTTIO ++ tristate "Ubicom UARTTIO support" ++ depends on UBICOM32=y ++ select SERIAL_CORE ++ default y ++ help ++ Add support for the Ubicom virtual peripherial serial interface. ++ ++config SERIAL_UBI32_UARTTIO_NR_UARTS ++ int "Maximum number of UARTTIO virtual serial ports" ++ depends on SERIAL_UBI32_UARTTIO ++ default "4" ++ help ++ Set this to the maximum number of serial ports you want the driver to support. ++ ++config SERIAL_UBI32_UARTTIO_CONSOLE ++ tristate "Ubicom UARTTIO console support" ++ depends on SERIAL_UBI32_UARTTIO=y ++ select SERIAL_CORE_CONSOLE ++ default y ++ help ++ Add support for console on the Ubicom virtual peripherial serial interface. ++ ++config SERIAL_UBI32_SERDES ++ bool "Ubicom serial port support" ++ depends on UBICOM32=y ++ select SERIAL_CORE ++ default y ++ help ++ Add support for the Ubicom serial interface. ++ ++config SERIAL_UBI32_SERDES_CONSOLE ++ bool "Ubicom serial console support" ++ depends on SERIAL_UBI32_SERDES=y ++ select SERIAL_CORE_CONSOLE ++ default y ++ ++config SERIAL_UBI32_MAILBOX ++ bool "Ubicom mailbox support" ++ depends on UBICOM32=y ++ select SERIAL_CORE ++ default n ++ help ++ Add support for the Ubicom mailbox interface. ++ ++config SERIAL_UBI32_MAILBOX_CONSOLE ++ bool "Ubicom mailbox console support" ++ depends on SERIAL_UBI32_MAILBOX=y ++ select SERIAL_CORE_CONSOLE ++ default y ++ + config SERIAL_SUNCORE + bool + depends on SPARC +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -81,3 +81,6 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks + obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o + obj-$(CONFIG_SERIAL_QE) += ucc_uart.o + obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o ++obj-$(CONFIG_SERIAL_UBI32_SERDES) += ubi32_serdes.o ++obj-$(CONFIG_SERIAL_UBI32_UARTTIO) += ubi32_uarttio.o ++obj-$(CONFIG_SERIAL_UBI32_MAILBOX) += ubi32_mailbox.o +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -214,6 +214,15 @@ config SPI_S3C24XX + help + SPI driver for Samsung S3C24XX series ARM SoCs + ++config SPI_UBICOM32_GPIO ++ tristate "Ubicom32 SPI over GPIO" ++ depends on SPI_MASTER && UBICOM32 && EXPERIMENTAL ++ select SPI_BITBANG ++ select HAS_DMA ++ help ++ SPI driver for the Ubicom32 architecture using ++ GPIO lines to provide the SPI bus. ++ + config SPI_S3C24XX_GPIO + tristate "Samsung S3C24XX series SPI by GPIO" + depends on ARCH_S3C2410 && EXPERIMENTAL +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -29,6 +29,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52x + obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o + obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o + obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o ++obj-$(CONFIG_SPI_UBICOM32_GPIO) += spi_ubicom32_gpio.o + obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o + obj-$(CONFIG_SPI_TXX9) += spi_txx9.o + obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o +--- a/drivers/uio/Kconfig ++++ b/drivers/uio/Kconfig +@@ -94,4 +94,12 @@ config UIO_PCI_GENERIC + primarily, for virtualization scenarios. + If you compile this as a module, it will be called uio_pci_generic. + ++config UIO_UBICOM32RING ++ tristate "Ubicom32 Ring Buffer driver" ++ default n ++ help ++ Userspace I/O interface for a Ubicom32 Ring Buffer. ++ ++ If you compile this as a module, it will be called uio_ubicom32ring ++ + endif +--- a/drivers/uio/Makefile ++++ b/drivers/uio/Makefile +@@ -6,3 +6,4 @@ obj-$(CONFIG_UIO_SMX) += uio_smx.o + obj-$(CONFIG_UIO_AEC) += uio_aec.o + obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o + obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o ++obj-$(CONFIG_UIO_UBICOM32RING) += uio_ubicom32ring.o +--- a/drivers/usb/gadget/epautoconf.c ++++ b/drivers/usb/gadget/epautoconf.c +@@ -154,6 +154,10 @@ ep_matches ( + /* configure your hardware with enough buffering!! */ + } + break; ++ ++ case USB_ENDPOINT_XFER_BULK: ++ if ((gadget->is_dualspeed) && (ep->maxpacket < 512)) ++ return 0; + } + + /* MATCH!! */ +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -22,6 +22,7 @@ config USB_ARCH_HAS_HCD + default y if PCMCIA && !M32R # sl811_cs + default y if ARM # SL-811 + default y if SUPERH # r8a66597-hcd ++ default y if UBICOM32 # Ubicom's onchip USB Duial role controller + default PCI + + # many non-PCI SOC chips embed OHCI +--- a/drivers/usb/musb/Kconfig ++++ b/drivers/usb/musb/Kconfig +@@ -14,7 +14,7 @@ config USB_MUSB_HDRC + select TWL4030_USB if MACH_OMAP_3430SDP + select NOP_USB_XCEIV if MACH_OMAP3EVM + select USB_OTG_UTILS +- tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' ++ tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, Ubicom, ...)' + help + Say Y here if your system has a dual role high speed USB + controller based on the Mentor Graphics silicon IP. Then +--- a/drivers/usb/musb/Makefile ++++ b/drivers/usb/musb/Makefile +@@ -30,6 +30,10 @@ ifeq ($(CONFIG_BF52x),y) + musb_hdrc-objs += blackfin.o + endif + ++ifeq ($(CONFIG_UBICOM32), y) ++ musb_hdrc-objs += ubi32_usb.o ++endif ++ + ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y) + musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o + endif +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -105,6 +105,13 @@ + #include + #endif + ++#ifdef CONFIG_UBICOM32 ++#include ++#include ++extern void ubi32_usb_init(void); ++extern void ubi32_usb_int_clr(void); ++#endif ++ + #include "musb_core.h" + + +@@ -148,8 +155,37 @@ static inline struct musb *dev_to_musb(s + } + + /*-------------------------------------------------------------------------*/ ++#if defined(CONFIG_UBICOM32) ++ ++/* ++ * Load an endpoint's FIFO ++ */ ++void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 wCount, const u8 *pSource) ++{ ++ void __iomem *fifo = hw_ep->fifo; ++ ++ prefetch((u8 *)pSource); ++ ++ DBG(4, "%cX ep%d fifo %p count %d buf %p\n", ++ 'T', hw_ep->epnum, fifo, wCount, pSource); ++ ++ usb_tio_write_fifo((u32)fifo, (u32)pSource, wCount); ++ ++} ++ ++/* ++ * Unload an endpoint's FIFO ++ */ ++void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 wCount, u8 *pDest) ++{ ++ ++ void __iomem *fifo = hw_ep->fifo; ++ DBG(4, "%cX ep%d fifo %p count %d buf %p\n", ++ 'R', hw_ep->epnum, fifo, wCount, pDest); ++ usb_tio_read_fifo((u32)fifo, (u32)pDest, wCount); ++} + +-#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN) ++#elif !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN) + + /* + * Load an endpoint's FIFO +@@ -228,8 +264,7 @@ void musb_read_fifo(struct musb_hw_ep *h + readsb(fifo, dst, len); + } + } +- +-#endif /* normal PIO */ ++#endif /* !T6010 && !BLACKFIN */ + + + /*-------------------------------------------------------------------------*/ +@@ -890,12 +925,19 @@ void musb_start(struct musb *musb) + musb_writeb(regs, MUSB_TESTMODE, 0); + + /* put into basic highspeed mode and start session */ ++#ifndef CONFIG_UBICOM32 + musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE + | MUSB_POWER_SOFTCONN + | MUSB_POWER_HSENAB + /* ENSUSPEND wedges tusb */ + /* | MUSB_POWER_ENSUSPEND */ + ); ++#else ++ musb_writeb(regs, MUSB_POWER, MUSB_POWER_HSENAB ++ /* ENSUSPEND wedges tusb */ ++ /* | MUSB_POWER_ENSUSPEND */ ++ ); ++#endif + + musb->is_active = 0; + devctl = musb_readb(regs, MUSB_DEVCTL); +@@ -1096,6 +1138,7 @@ static struct fifo_cfg __initdata mode_4 + }; + + ++#ifndef CONFIG_UBICOM32 + /* + * configure a fifo; for non-shared endpoints, this may be called + * once for a tx fifo and once for an rx fifo. +@@ -1255,7 +1298,7 @@ static int __init ep_config_from_table(s + + return 0; + } +- ++#endif /* CONFIG_UBICOM32 */ + + /* + * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false +@@ -1271,6 +1314,11 @@ static int __init ep_config_from_hw(stru + DBG(2, "<== static silicon ep config\n"); + + /* FIXME pick up ep0 maxpacket size */ ++#ifdef CONFIG_UBICOM32 ++ /* set ep0 to shared_fifo, otherwise urb will be put to out_qh but ep0_irq try to get the urb from in_qh*/ ++ hw_ep = musb->endpoints; ++ hw_ep->is_shared_fifo = true; ++#endif + + for (epnum = 1; epnum < musb->config->num_eps; epnum++) { + musb_ep_select(mbase, epnum); +@@ -1291,14 +1339,27 @@ static int __init ep_config_from_hw(stru + /* REVISIT: this algorithm is lazy, we should at least + * try to pick a double buffered endpoint. + */ ++#ifndef CONFIG_UBICOM32 + if (musb->bulk_ep) + continue; + musb->bulk_ep = hw_ep; ++#else ++ if ((musb->bulk_ep_in) && (musb->bulk_ep_out)) ++ continue; ++ /* Save theEP with 1024 Bytes FIFO for ISO */ ++ if(hw_ep->max_packet_sz_tx == 512) { ++ if (!musb->bulk_ep_in) { ++ musb->bulk_ep_in = hw_ep; ++ } else if (!musb->bulk_ep_out) { ++ musb->bulk_ep_out = hw_ep; ++ } ++ } ++#endif /* CONFIG_UBICOM32 */ + #endif + } + + #ifdef CONFIG_USB_MUSB_HDRC_HCD +- if (!musb->bulk_ep) { ++ if ((!musb->bulk_ep_in) || (!musb->bulk_ep_out)) { + pr_debug("%s: missing bulk\n", musb_driver_name); + return -EINVAL; + } +@@ -1407,12 +1468,16 @@ static int __init musb_core_init(u16 mus + musb->epmask = 1; + + if (reg & MUSB_CONFIGDATA_DYNFIFO) { ++#ifndef CONFIG_UBICOM32 + if (musb->config->dyn_fifo) + status = ep_config_from_table(musb); +- else { ++ else ++#endif ++ { + ERR("reconfigure software for Dynamic FIFOs\n"); + status = -ENODEV; + } ++ + } else { + if (!musb->config->dyn_fifo) + status = ep_config_from_hw(musb); +@@ -1476,8 +1541,8 @@ static int __init musb_core_init(u16 mus + + /*-------------------------------------------------------------------------*/ + +-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) +- ++#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_UBICOM32) ++static u32_t musb_int_count = 0; + static irqreturn_t generic_interrupt(int irq, void *__hci) + { + unsigned long flags; +@@ -1486,10 +1551,17 @@ static irqreturn_t generic_interrupt(int + + spin_lock_irqsave(&musb->lock, flags); + ++#ifndef CONFIG_UBICOM32 + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); ++#else ++ musb_read_int_status(&musb->int_usb, &musb->int_tx, &musb->int_rx); ++ //ubi32_usb_int_clr(); ++ musb_int_count++; ++#endif + ++ DBG(4, "usb %x, tx %x, rx %x", musb->int_usb, musb->int_tx, musb->int_rx); + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + +@@ -2241,6 +2313,10 @@ static struct platform_driver musb_drive + + static int __init musb_init(void) + { ++#ifdef CONFIG_UBICOM32 ++ ubi32_usb_init(); ++#endif ++ + #ifdef CONFIG_USB_MUSB_HDRC_HCD + if (usb_disabled()) + return 0; +--- a/drivers/usb/musb/musb_core.h ++++ b/drivers/usb/musb/musb_core.h +@@ -339,7 +339,12 @@ struct musb { + * queue until it completes or NAKs too much; then we try the next + * endpoint. + */ ++#ifdef CONFIG_UBICOM32 ++ struct musb_hw_ep *bulk_ep_in; ++ struct musb_hw_ep *bulk_ep_out; ++#else + struct musb_hw_ep *bulk_ep; ++#endif + + struct list_head control; /* of musb_qh */ + struct list_head in_bulk; /* of musb_qh */ +--- a/drivers/usb/musb/musb_gadget.c ++++ b/drivers/usb/musb/musb_gadget.c +@@ -434,7 +434,7 @@ void musb_g_tx(struct musb *musb, u8 epn + * probably rates reporting as a host error + */ + if (csr & MUSB_TXCSR_P_SENTSTALL) { +- csr |= MUSB_TXCSR_P_WZC_BITS; ++ csr &= ~(MUSB_TXCSR_P_WZC_BITS); + csr &= ~MUSB_TXCSR_P_SENTSTALL; + musb_writew(epio, MUSB_TXCSR, csr); + break; +@@ -442,7 +442,7 @@ void musb_g_tx(struct musb *musb, u8 epn + + if (csr & MUSB_TXCSR_P_UNDERRUN) { + /* we NAKed, no big deal ... little reason to care */ +- csr |= MUSB_TXCSR_P_WZC_BITS; ++ csr &= ~(MUSB_TXCSR_P_WZC_BITS); + csr &= ~(MUSB_TXCSR_P_UNDERRUN + | MUSB_TXCSR_TXPKTRDY); + musb_writew(epio, MUSB_TXCSR, csr); +@@ -577,12 +577,18 @@ static void rxstate(struct musb *musb, s + { + const u8 epnum = req->epnum; + struct usb_request *request = &req->request; +- struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out; ++ struct musb_ep *musb_ep = NULL; + void __iomem *epio = musb->endpoints[epnum].regs; +- unsigned fifo_count = 0; +- u16 len = musb_ep->packet_sz; ++ u16 fifo_count = 0; ++ u16 len = 0; + u16 csr = musb_readw(epio, MUSB_RXCSR); + ++ if (musb->endpoints[epnum].is_shared_fifo) ++ musb_ep = &musb->endpoints[epnum].ep_in; ++ else ++ musb_ep = &musb->endpoints[epnum].ep_out; ++ len = musb_ep->packet_sz; ++ + /* We shouldn't get here while DMA is active, but we do... */ + if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { + DBG(4, "DMA pending...\n"); +@@ -730,7 +736,7 @@ static void rxstate(struct musb *musb, s + */ + + /* ack the read! */ +- csr |= MUSB_RXCSR_P_WZC_BITS; ++ csr &= ~MUSB_RXCSR_P_WZC_BITS; + csr &= ~MUSB_RXCSR_RXPKTRDY; + musb_writew(epio, MUSB_RXCSR, csr); + } +@@ -749,10 +755,15 @@ void musb_g_rx(struct musb *musb, u8 epn + u16 csr; + struct usb_request *request; + void __iomem *mbase = musb->mregs; +- struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out; ++ struct musb_ep *musb_ep = NULL; + void __iomem *epio = musb->endpoints[epnum].regs; + struct dma_channel *dma; + ++ if (musb->endpoints[epnum].is_shared_fifo) ++ musb_ep = &musb->endpoints[epnum].ep_in; ++ else ++ musb_ep = &musb->endpoints[epnum].ep_out; ++ + musb_ep_select(mbase, epnum); + + request = next_request(musb_ep); +@@ -1756,7 +1767,9 @@ int usb_gadget_register_driver(struct us + } + } + } +- ++#ifndef CONFIG_USB_MUSB_OTG ++ musb_pullup(musb, 1); ++#endif + return retval; + } + EXPORT_SYMBOL(usb_gadget_register_driver); +--- a/drivers/usb/musb/musb_gadget_ep0.c ++++ b/drivers/usb/musb/musb_gadget_ep0.c +@@ -241,14 +241,14 @@ __acquires(musb->lock) + case USB_REQ_SET_ADDRESS: + /* change it after the status stage */ + musb->set_address = true; +- musb->address = (u8) (ctrlrequest->wValue & 0x7f); ++ musb->address = (u8) (le16_to_cpu(ctrlrequest->wValue) & 0x7f); + handled = 1; + break; + + case USB_REQ_CLEAR_FEATURE: + switch (recip) { + case USB_RECIP_DEVICE: +- if (ctrlrequest->wValue ++ if (le16_to_cpu(ctrlrequest->wValue) + != USB_DEVICE_REMOTE_WAKEUP) + break; + musb->may_wakeup = 0; +@@ -262,8 +262,8 @@ __acquires(musb->lock) + + if (num == 0 + || num >= MUSB_C_NUM_EPS +- || ctrlrequest->wValue +- != USB_ENDPOINT_HALT) ++ || le16_to_cpu(ctrlrequest->wValue ++ != USB_ENDPOINT_HALT)) + break; + + if (ctrlrequest->wIndex & USB_DIR_IN) +@@ -293,7 +293,7 @@ __acquires(musb->lock) + switch (recip) { + case USB_RECIP_DEVICE: + handled = 1; +- switch (ctrlrequest->wValue) { ++ switch (le16_to_cpu(ctrlrequest->wValue)) { + case USB_DEVICE_REMOTE_WAKEUP: + musb->may_wakeup = 1; + break; +@@ -375,8 +375,8 @@ stall: + + if (epnum == 0 + || epnum >= MUSB_C_NUM_EPS +- || ctrlrequest->wValue +- != USB_ENDPOINT_HALT) ++ || le16_to_cpu(ctrlrequest->wValue ++ != USB_ENDPOINT_HALT)) + break; + + ep = musb->endpoints + epnum; +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -160,7 +160,11 @@ static inline void musb_h_tx_start(struc + /* NOTE: no locks here; caller should lock and select EP */ + if (ep->epnum) { + txcsr = musb_readw(ep->regs, MUSB_TXCSR); ++#ifndef CONFIG_UBICOM32 + txcsr |= MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_H_WZC_BITS; ++#else ++ txcsr |= (MUSB_TXCSR_TXPKTRDY & (~MUSB_TXCSR_H_WZC_BITS)); ++#endif + musb_writew(ep->regs, MUSB_TXCSR, txcsr); + } else { + txcsr = MUSB_CSR0_H_SETUPPKT | MUSB_CSR0_TXPKTRDY; +@@ -235,6 +239,8 @@ musb_start_urb(struct musb *musb, int is + break; + default: /* bulk, interrupt */ + /* actual_length may be nonzero on retry paths */ ++ if (urb->actual_length) ++ DBG(3 ,"musb_start_urb: URB %p retried, len: %d\n", urb, urb->actual_length); + buf = urb->transfer_buffer + urb->actual_length; + len = urb->transfer_buffer_length - urb->actual_length; + } +@@ -532,7 +538,11 @@ musb_host_packet_rx(struct musb *musb, s + musb_read_fifo(hw_ep, length, buf); + + csr = musb_readw(epio, MUSB_RXCSR); ++#ifndef CONFIG_UBICOM32 + csr |= MUSB_RXCSR_H_WZC_BITS; ++#else ++ csr &= ~MUSB_RXCSR_H_WZC_BITS; ++#endif + if (unlikely(do_flush)) + musb_h_flush_rxfifo(hw_ep, csr); + else { +@@ -566,6 +576,7 @@ musb_rx_reinit(struct musb *musb, struct + + /* if programmed for Tx, put it in RX mode */ + if (ep->is_shared_fifo) { ++#ifndef CONFIG_UBICOM32 + csr = musb_readw(ep->regs, MUSB_TXCSR); + if (csr & MUSB_TXCSR_MODE) { + musb_h_tx_flush_fifo(ep); +@@ -580,7 +591,18 @@ musb_rx_reinit(struct musb *musb, struct + */ + if (csr & MUSB_TXCSR_DMAMODE) + musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE); ++ ++#else ++ /* clear mode (and everything else) to enable Rx */ + musb_writew(ep->regs, MUSB_TXCSR, 0); ++ /* scrub all previous state, clearing toggle */ ++ csr = musb_readw(ep->regs, MUSB_RXCSR); ++ if (csr & MUSB_RXCSR_RXPKTRDY) ++ WARNING("rx%d, packet/%d ready?\n", ep->epnum, ++ musb_readw(ep->regs, MUSB_RXCOUNT)); ++ ++ musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); ++#endif + + /* scrub all previous state, clearing toggle */ + } else { +@@ -1108,6 +1130,16 @@ void musb_host_tx(struct musb *musb, u8 + void __iomem *mbase = musb->mregs; + struct dma_channel *dma; + ++#ifdef CONFIG_UBICOM32 ++ if (hw_ep->is_shared_fifo) { ++ qh = hw_ep->in_qh; ++ } ++#ifdef CONFIG_USB_SERIAL_SIERRAWIRELESS ++ printk(KERN_DEBUG "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr, ++ dma ? ", dma" : ""); ++#endif ++#endif ++ + musb_ep_select(mbase, epnum); + tx_csr = musb_readw(epio, MUSB_TXCSR); + +@@ -1148,9 +1180,14 @@ void musb_host_tx(struct musb *musb, u8 + * we have a candidate... NAKing is *NOT* an error + */ + musb_ep_select(mbase, epnum); ++#ifndef CONFIG_UBICOM32 + musb_writew(epio, MUSB_TXCSR, + MUSB_TXCSR_H_WZC_BITS + | MUSB_TXCSR_TXPKTRDY); ++#else ++ musb_writew(epio, MUSB_TXCSR, ++ MUSB_TXCSR_TXPKTRDY); ++#endif + return; + } + +@@ -1324,8 +1361,14 @@ void musb_host_tx(struct musb *musb, u8 + qh->segsize = length; + + musb_ep_select(mbase, epnum); ++#ifndef CONFIG_UBICOM32 ++ musb_writew(epio, MUSB_TXCSR, ++ MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); ++#else + musb_writew(epio, MUSB_TXCSR, +- MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); ++ MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY); ++#endif ++ + } + + +@@ -1385,7 +1428,11 @@ static void musb_bulk_rx_nak_timeout(str + + /* clear nak timeout bit */ + rx_csr = musb_readw(epio, MUSB_RXCSR); ++#ifndef CONFIG_UBICOM32 + rx_csr |= MUSB_RXCSR_H_WZC_BITS; ++#else ++ rx_csr &= ~MUSB_RXCSR_H_WZC_BITS; ++#endif + rx_csr &= ~MUSB_RXCSR_DATAERROR; + musb_writew(epio, MUSB_RXCSR, rx_csr); + +@@ -1454,6 +1501,13 @@ void musb_host_rx(struct musb *musb, u8 + + pipe = urb->pipe; + ++#ifdef CONFIG_UBICOM32 ++#ifdef CONFIG_USB_SERIAL_SIERRAWIRELESS ++ printk(KERN_DEBUG "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr, ++ xfer_len, dma ? ", dma" : ""); ++#endif ++#endif ++ + DBG(5, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n", + epnum, rx_csr, urb->actual_length, + dma ? dma->actual_len : 0); +@@ -1492,8 +1546,15 @@ void musb_host_rx(struct musb *musb, u8 + return; + } + musb_ep_select(mbase, epnum); ++#ifndef CONFIG_UBICOM32 + rx_csr |= MUSB_RXCSR_H_WZC_BITS; + rx_csr &= ~MUSB_RXCSR_DATAERROR; ++#else ++ /* NEED TO EVALUATE CHANGE */ ++ rx_csr &= ~MUSB_RXCSR_H_WZC_BITS; ++ rx_csr &= ~MUSB_RXCSR_DATAERROR; ++// musb_writew(epio, MUSB_RXCSR, (~(MUSB_RXCSR_H_WZC_BITS))| MUSB_RXCSR_H_REQPKT); ++#endif + musb_writew(epio, MUSB_RXCSR, rx_csr); + + goto finish; +@@ -1554,8 +1615,13 @@ void musb_host_rx(struct musb *musb, u8 + rx_csr &= ~MUSB_RXCSR_H_REQPKT; + + musb_ep_select(mbase, epnum); ++#ifndef CONFIG_UBICOM32 + musb_writew(epio, MUSB_RXCSR, + MUSB_RXCSR_H_WZC_BITS | rx_csr); ++#else ++ musb_writew(epio, MUSB_RXCSR, ++ (~MUSB_RXCSR_H_WZC_BITS) & rx_csr); ++#endif + } + #endif + if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) { +@@ -1585,7 +1651,7 @@ void musb_host_rx(struct musb *musb, u8 + else + done = false; + +- } else { ++ } else { + /* done if urb buffer is full or short packet is recd */ + done = (urb->actual_length + xfer_len >= + urb->transfer_buffer_length +@@ -1799,7 +1865,11 @@ static int musb_schedule( + if (musb_ep_get_qh(hw_ep, is_in) != NULL) + continue; + ++#ifndef CONFIG_UBICOM32 + if (hw_ep == musb->bulk_ep) ++#else ++ if ((hw_ep == musb->bulk_ep_in) || (hw_ep == musb->bulk_ep_out)) /* Ubicom */ ++#endif + continue; + + if (is_in) +@@ -1813,7 +1883,14 @@ static int musb_schedule( + best_end = epnum; + } + } ++ ++#ifdef CONFIG_UBICOM32 ++ if (((best_diff >= qh->maxpacket)) && ((qh->type == USB_ENDPOINT_XFER_BULK) && (!is_in))) ++ best_end = -1; ++#endif ++ + /* use bulk reserved ep1 if no other ep is free */ ++#ifndef CONFIG_UBICOM32 + if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) { + hw_ep = musb->bulk_ep; + if (is_in) +@@ -1835,6 +1912,22 @@ static int musb_schedule( + } else if (best_end < 0) { + return -ENOSPC; + } ++#else ++ if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) { ++ /* hw_ep = musb->bulk_ep; */ ++ if (is_in) { ++ head = &musb->in_bulk; ++ hw_ep = musb->bulk_ep_in; /* UBICOM */ ++ } ++ else { ++ head = &musb->out_bulk; ++ hw_ep = musb->bulk_ep_out; /* UBICOM */ ++ } ++ goto success; ++ } else if (best_end < 0) { ++ return -ENOSPC; ++ } ++#endif + + idle = 1; + qh->mux = 0; +@@ -1846,6 +1939,13 @@ success: + list_add_tail(&qh->ring, head); + qh->mux = 1; + } ++ /* ++ * It's not make sense to set NAK timeout when qh->mux = 0, ++ * There is nothing else to schedule ++ */ ++ if ((qh->type == USB_ENDPOINT_XFER_BULK) && (qh->mux == 0)) ++ qh->intv_reg = 0; ++ + qh->hw_ep = hw_ep; + qh->hep->hcpriv = qh; + if (idle) +@@ -1964,6 +2064,15 @@ static int musb_urb_enqueue( + /* ISO always uses logarithmic encoding */ + interval = min_t(u8, epd->bInterval, 16); + break; ++#ifdef COMFIG_UBICOM32 ++ case USB_ENDPOINT_XFER_BULK: ++ if (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ++ interval = (USB_SPEED_HIGH == urb->dev->speed) ? 16: 2; ++ else ++ interval = 0; ++ break; ++#endif ++ + default: + /* REVISIT we actually want to use NAK limits, hinting to the + * transfer scheduling logic to try some other qh, e.g. try +--- a/drivers/usb/musb/musb_io.h ++++ b/drivers/usb/musb/musb_io.h +@@ -58,6 +58,7 @@ static inline void writesb(const void __ + + #ifndef CONFIG_BLACKFIN + ++#ifndef CONFIG_UBICOM32 + /* NOTE: these offsets are all in bytes */ + + static inline u16 musb_readw(const void __iomem *addr, unsigned offset) +@@ -72,7 +73,37 @@ static inline void musb_writew(void __io + + static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) + { __raw_writel(data, addr + offset); } ++#else ++#include ++static inline u16 musb_readw(const void __iomem *addr, unsigned offset) ++{ ++ u16 data; ++ usb_tio_read_u16((u32)(addr + offset), &data); ++ return data; ++} + ++static inline u8 musb_readb(const void __iomem *addr, unsigned offset) ++{ ++ u8 data; ++ usb_tio_read_u8((u32)(addr + offset), &data); ++ return data; ++} ++ ++static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data) ++{ ++ usb_tio_write_u16((u32)(addr + offset), data); ++} ++ ++static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) ++{ ++ usb_tio_write_u8((u32)(addr + offset), data); ++} ++ ++static inline void musb_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx) ++{ ++ return usb_tio_read_int_status(int_usb, int_tx, int_rx); ++} ++#endif /* CONFIG_UBICOM32 */ + + #ifdef CONFIG_USB_TUSB6010 + +@@ -106,7 +137,7 @@ static inline void musb_writeb(void __io + __raw_writew(tmp, addr + (offset & ~1)); + } + +-#else ++#elif !defined(CONFIG_UBICOM32) + + static inline u8 musb_readb(const void __iomem *addr, unsigned offset) + { return __raw_readb(addr + offset); } +--- a/drivers/usb/musb/musb_regs.h ++++ b/drivers/usb/musb/musb_regs.h +@@ -167,6 +167,7 @@ + (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \ + | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY) + ++ + /* RXCSR in Peripheral and Host mode */ + #define MUSB_RXCSR_AUTOCLEAR 0x8000 + #define MUSB_RXCSR_DMAENAB 0x2000 +--- a/drivers/video/backlight/Kconfig ++++ b/drivers/video/backlight/Kconfig +@@ -100,6 +100,63 @@ config LCD_HP700 + If you have an HP Jornada 700 series handheld (710/720/728) + say Y to enable LCD control driver. + ++config LCD_UBICOM32POWER ++ tristate "Ubicom LCD power Driver" ++ depends on LCD_CLASS_DEVICE && UBICOM32 ++ default n ++ help ++ If you have a Ubicom32 based system with an LCD panel that requires ++ power control, say Y to enable the power control driver for it. ++ ++config LCD_UBICOM32 ++ tristate "Ubicom Backlight Driver" ++ depends on LCD_CLASS_DEVICE && UBICOM32 ++ default n ++ help ++ This driver takes care of initialization of LCD panels with ++ built in controllers. ++ ++menu "Ubicom32 LCD Panel Support" ++ depends on UBICOM32 && LCD_UBICOM32 ++ ++config LCD_UBICOM32_TFT2N0369E_P ++ bool "TFT2N0369E (Portrait)" ++ default n ++ help ++ Support for TFT2N0369 in portrait mode ++ ++config LCD_UBICOM32_TFT2N0369E_L ++ bool "TFT2N0369E (Landscape)" ++ default n ++ help ++ Support for TFT2N0369 in landscape mode ++ ++config LCD_UBICOM32_CFAF240320KTTS ++ bool "CFAF240320KTTS" ++ default n ++ help ++ Support for CFAF240320KTTS ++ ++config LCD_UBICOM32_CFAF240320KTTS_180 ++ bool "CFAF240320KTTS (180 rotation)" ++ default n ++ help ++ Support for CFAF240320KTTS rotated 180 degrees ++ ++config LCD_UBICOM32_CFAF240320D ++ bool "CFAF240320D" ++ default n ++ help ++ Support for CFAF240320D ++ ++config LCD_UBICOM32_CFAF320240F ++ bool "CFAF320240F" ++ default n ++ help ++ Support for CFAF320240F ++ ++endmenu ++ + # + # Backlight + # +@@ -262,3 +319,11 @@ config BACKLIGHT_ADP5520 + To compile this driver as a module, choose M here: the module will + be called adp5520_bl. + ++config BACKLIGHT_UBICOM32 ++ tristate "Ubicom Backlight Driver" ++ depends on BACKLIGHT_CLASS_DEVICE && UBICOM32 ++ default n ++ help ++ If you have a Ubicom32 based system with a backlight say Y to enable the ++ backlight driver. ++ +--- a/drivers/video/backlight/Makefile ++++ b/drivers/video/backlight/Makefile +@@ -10,6 +10,9 @@ obj-$(CONFIG_LCD_PLATFORM) += platfor + obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o + obj-$(CONFIG_LCD_TDO24M) += tdo24m.o + obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o ++obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o ++obj-$(CONFIG_LCD_UBICOM32POWER) += ubicom32lcdpower.o ++obj-$(CONFIG_LCD_UBICOM32) += ubicom32lcd.o + + obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o + obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o +@@ -28,4 +31,4 @@ obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886 + obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o + obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o + obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o +- ++obj-$(CONFIG_BACKLIGHT_UBICOM32) += ubicom32bl.o +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -611,6 +611,50 @@ config FB_BFIN_T350MCQB + This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI + It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. + ++config FB_UBICOM32 ++ tristate "Ubicom32 Frame Buffer driver" ++ depends on FB && UBICOM32 ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ select FONT_6x11 if FRAMEBUFFER_CONSOLE ++ help ++ This is the framebuffer device driver for the Ubicom32 architecture. ++ You can configure video memory by using kernel command line parameters, for example: ++ video=ubicomfb:vram_size=512,init_value=0xffff ++ ++config FB_UBICOM32_PLIO80 ++ tristate "Ubicom32 80 Bus PLIO Frame Buffer driver" ++ depends on FB && UBICOM32 ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ select FONT_6x11 if FRAMEBUFFER_CONSOLE ++ select UBICOM32_PLIO ++ help ++ This is a framebuffer device driver for the Ubicom32 architecture. ++ You can configure the xres, yres and vram size (in kilobytes) by using ++ kernel command line parameters, for example: ++ video=ubicom32vfb:xres=320,yres=240,vram_size=512 ++ ++config FB_UBICOM32_VIRTUAL ++ tristate "Ubicom32 Virtual Frame Buffer driver" ++ depends on FB && UBICOM32 ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ select FONT_6x11 if FRAMEBUFFER_CONSOLE ++ help ++ This is a virtual framebuffer device driver for the Ubicom32 architecture. ++ You can configure the xres, yres and vram size (in kilobytes) by using ++ kernel command line parameters, for example: ++ video=ubicom32vfb:xres=320,yres=240,vram_size=512 ++ ++config FB_UBICOM32_VIRTUAL_NOAUTO ++ bool "Do not automatically load" ++ depends on FB_UBICOM32_VIRTUAL ++ help ++ Select this option to prevent the VFB from automatically loading at boot. + + config FB_STI + tristate "HP STI frame buffer device support" +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -140,6 +140,10 @@ obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin + obj-$(CONFIG_FB_MX3) += mx3fb.o + obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o + ++obj-$(CONFIG_FB_UBICOM32) += ubicom32fb.o ++obj-$(CONFIG_FB_UBICOM32_PLIO80) += ubicom32plio80.o ++obj-$(CONFIG_FB_UBICOM32_VIRTUAL) += ubicom32vfb.o ++ + # the test framebuffer is last + obj-$(CONFIG_FB_VIRTUAL) += vfb.o + +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -973,6 +973,19 @@ config WATCHDOG_RIO + machines. The watchdog timeout period is normally one minute but + can be changed with a boot-time parameter. + ++# Ubicom32 ++ ++config UBI32_WDT ++ tristate "Ubicom32 Hardware Watchdog support" ++ depends on UBICOM32 ++ ---help--- ++ If you say yes here you will get support for the Ubicom32 On-Chip ++ Watchdog Timer. If you have one of these processors and wish to ++ have watchdog support enabled, say Y, otherwise say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ubi32_wdt. ++ + # XTENSA Architecture + + # +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -139,6 +139,9 @@ obj-$(CONFIG_SH_WDT) += shwdt.o + obj-$(CONFIG_WATCHDOG_RIO) += riowd.o + obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o + ++# Ubicom32 Architecture ++obj-$(CONFIG_UBI32_WDT) += ubi32_wdt.o ++ + # XTENSA Architecture + + # Architecture Independant +--- a/fs/binfmt_flat.c ++++ b/fs/binfmt_flat.c +@@ -67,6 +67,11 @@ + #define FLAT_DATA_ALIGN (sizeof(void *)) + #endif + ++#ifndef ARCH_FLAT_ALIGN ++#undef FLAT_DATA_ALIGN ++#define FLAT_DATA_ALIGN ARCH_FLAT_ALIGN ++#endif ++ + #define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ + #define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ + +@@ -434,6 +439,7 @@ static int load_flat_file(struct linux_b + loff_t fpos; + unsigned long start_code, end_code; + int ret; ++ int flush_happened = 0; + + hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ + inode = bprm->file->f_path.dentry->d_inode; +@@ -520,6 +526,7 @@ static int load_flat_file(struct linux_b + /* OK, This is the point of no return */ + set_personality(PER_LINUX_32BIT); + setup_new_exec(bprm); ++ flush_happened = 1; + } + + /* +@@ -534,6 +541,12 @@ static int load_flat_file(struct linux_b + * it all together. + */ + if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) { ++ ++#ifdef ARCH_FLAT_ALIGN_TEXT ++ printk("Unable to mmap rom with ARCH alignment requirements\n"); ++ ret = -ENOEXEC; ++ goto err; ++#endif + /* + * this should give us a ROM ptr, but if it doesn't we don't + * really care +@@ -552,7 +565,7 @@ static int load_flat_file(struct linux_b + goto err; + } + +- len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); ++ len = data_len + extra + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN); + len = PAGE_ALIGN(len); + down_write(¤t->mm->mmap_sem); + realdatastart = do_mmap(0, 0, len, +@@ -571,6 +584,7 @@ static int load_flat_file(struct linux_b + datapos = ALIGN(realdatastart + + MAX_SHARED_LIBS * sizeof(unsigned long), + FLAT_DATA_ALIGN); ++ //datapos = realdatastart + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), ARCH_FLAT_ALIGN); + + DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n", + (int)(data_len + bss_len + stack_len), (int)datapos); +@@ -599,7 +613,11 @@ static int load_flat_file(struct linux_b + memp_size = len; + } else { + +- len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); ++ len = text_len + data_len + extra + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN); ++#ifdef ARCH_FLAT_ALIGN_TEXT ++ /* Reserve space for the text alignment. */ ++ len += FLAT_DATA_ALIGN; ++#endif + len = PAGE_ALIGN(len); + down_write(¤t->mm->mmap_sem); + textpos = do_mmap(0, 0, len, +@@ -615,10 +633,17 @@ static int load_flat_file(struct linux_b + goto err; + } + ++ memp = textpos; ++#ifdef ARCH_FLAT_ALIGN_TEXT ++ textpos = ALIGN(textpos + sizeof(struct flat_hdr), FLAT_DATA_ALIGN) - sizeof(struct flat_hdr); ++#endif + realdatastart = textpos + ntohl(hdr->data_start); + datapos = ALIGN(realdatastart + + MAX_SHARED_LIBS * sizeof(unsigned long), + FLAT_DATA_ALIGN); ++// datapos = realdatastart + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), ARCH_FLAT_ALIGN); ++// reloc = (unsigned long *) (textpos + ntohl(hdr->reloc_start) + ++// ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), ARCH_FLAT_ALIGN)); + + reloc = (unsigned long *) + (datapos + (ntohl(hdr->reloc_start) - text_len)); +@@ -658,7 +683,7 @@ static int load_flat_file(struct linux_b + } + if (IS_ERR_VALUE(result)) { + printk("Unable to read code+data+bss, errno %d\n",(int)-result); +- do_munmap(current->mm, textpos, text_len + data_len + extra + ++ do_munmap(current->mm, memp, text_len + data_len + extra + + MAX_SHARED_LIBS * sizeof(unsigned long)); + ret = result; + goto err; +@@ -671,6 +696,9 @@ static int load_flat_file(struct linux_b + + /* The main program needs a little extra setup in the task structure */ + start_code = textpos + sizeof (struct flat_hdr); ++#ifdef ARCH_FLAT_ALIGN_TEXT ++ BUG_ON(ALIGN(start_code, FLAT_DATA_ALIGN) != start_code); ++#endif + end_code = textpos + text_len; + if (id == 0) { + current->mm->start_code = start_code; +@@ -799,6 +827,13 @@ static int load_flat_file(struct linux_b + + return 0; + err: ++ if (flush_happened) { ++ /* ++ * The parent process has already started running. We cannot allow the child to return back to user space ++ * as this child is still uning the parent stack and 2 will clobber each other. We are going to kill this child. ++ */ ++ do_exit(SIGTERM); ++ } + return ret; + } + +--- a/fs/Kconfig.binfmt ++++ b/fs/Kconfig.binfmt +@@ -30,7 +30,7 @@ config COMPAT_BINFMT_ELF + config BINFMT_ELF_FDPIC + bool "Kernel support for FDPIC ELF binaries" + default y +- depends on (FRV || BLACKFIN || (SUPERH32 && !MMU)) ++ depends on (FRV || BLACKFIN || (SUPERH32 && !MMU) || UBICOM32) + help + ELF FDPIC binaries are based on ELF, but allow the individual load + segments of a binary to be located in memory independently of each +--- a/include/asm-generic/resource.h ++++ b/include/asm-generic/resource.h +@@ -69,13 +69,16 @@ + /* + * boot-time rlimit defaults for the init task: + */ ++#ifndef CONFIG_ELF_CORE ++#define CONFIG_USER_ELF_CORE_SIZE 0 ++#endif + #define INIT_RLIMITS \ + { \ + [RLIMIT_CPU] = { RLIM_INFINITY, RLIM_INFINITY }, \ + [RLIMIT_FSIZE] = { RLIM_INFINITY, RLIM_INFINITY }, \ + [RLIMIT_DATA] = { RLIM_INFINITY, RLIM_INFINITY }, \ + [RLIMIT_STACK] = { _STK_LIM, _STK_LIM_MAX }, \ +- [RLIMIT_CORE] = { 0, RLIM_INFINITY }, \ ++ [RLIMIT_CORE] = { CONFIG_USER_ELF_CORE_SIZE, RLIM_INFINITY }, \ + [RLIMIT_RSS] = { RLIM_INFINITY, RLIM_INFINITY }, \ + [RLIMIT_NPROC] = { 0, 0 }, \ + [RLIMIT_NOFILE] = { INR_OPEN, INR_OPEN }, \ +--- a/include/linux/elf-em.h ++++ b/include/linux/elf-em.h +@@ -41,6 +41,7 @@ + * up with a final number. + */ + #define EM_ALPHA 0x9026 ++#define EM_UBICOM32 0xde3d /* Ubicom32; no ABI */ + + /* Bogus old v850 magic number, used by old tools. */ + #define EM_CYGNUS_V850 0x9080 +--- a/include/linux/fb.h ++++ b/include/linux/fb.h +@@ -152,6 +152,10 @@ struct dentry; + #define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */ + #define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */ + ++#define FB_ACCEL_UBICOM32 0x0100 /* Ubicom32 */ ++#define FB_ACCEL_UBICOM32_VFB 0x0101 /* Ubicom32 VFB */ ++#define FB_ACCEL_UBICOM32_PLIO80 0x0102 /* Ubicom32 PLIO80 */ ++ + struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ +--- a/include/linux/if_ppp.h ++++ b/include/linux/if_ppp.h +@@ -114,14 +114,14 @@ struct pppol2tp_ioc_stats { + __u16 tunnel_id; /* redundant */ + __u16 session_id; /* if zero, get tunnel stats */ + __u32 using_ipsec:1; /* valid only for session_id == 0 */ +- aligned_u64 tx_packets; +- aligned_u64 tx_bytes; +- aligned_u64 tx_errors; +- aligned_u64 rx_packets; +- aligned_u64 rx_bytes; +- aligned_u64 rx_seq_discards; +- aligned_u64 rx_oos_packets; +- aligned_u64 rx_errors; ++ __u64 tx_packets; ++ __u64 tx_bytes; ++ __u64 tx_errors; ++ __u64 rx_packets; ++ __u64 rx_bytes; ++ __u64 rx_seq_discards; ++ __u64 rx_oos_packets; ++ __u64 rx_errors; + }; + + #define ifr__name b.ifr_ifrn.ifrn_name +--- a/include/linux/oprofile.h ++++ b/include/linux/oprofile.h +@@ -102,6 +102,8 @@ void oprofile_add_sample(struct pt_regs + */ + void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, + unsigned long event, int is_kernel); ++void oprofile_add_ext_sample_cpu(unsigned long pc, struct pt_regs * const regs, ++ unsigned long event, int is_kernel, int cpu); + + /* Use this instead when the PC value is not from the regs. Doesn't + * backtrace. */ +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -179,6 +179,9 @@ + /* BCM63xx family SoCs */ + #define PORT_BCM63XX 89 + ++/* Ubicom32 */ ++#define PORT_UBI32_UARTTIO 87 ++ + #ifdef __KERNEL__ + + #include +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -328,4 +328,14 @@ static inline void *kzalloc_node(size_t + + void __init kmem_cache_init_late(void); + ++struct kmem_cache_size_info { ++ unsigned short page; ++ unsigned short order; ++}; ++ ++/* ++ * get info on all the memory allocated by slab for this named cache ++ */ ++extern int kmem_cache_block_info(char *name, struct kmem_cache_size_info *data, int max_data); ++ + #endif /* _LINUX_SLAB_H */ +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -844,6 +844,12 @@ config ELF_CORE + help + Enable support for generating core dumps. Disabling saves about 4k. + ++config USER_ELF_CORE_SIZE ++ int "user core dump size (10MB to 32MB)" ++ range 10485760 33554432 ++ default 16777216 ++ depends on ELF_CORE ++ + config PCSPKR_PLATFORM + bool "Enable PC-Speaker support" if EMBEDDED + depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2945,6 +2945,9 @@ static int m_show(struct seq_file *m, vo + /* Used by oprofile and other similar tools. */ + seq_printf(m, " 0x%p", mod->module_core); + ++#ifdef ARCH_PROC_MODULES_EXTRA ++ ARCH_PROC_MODULES_EXTRA(m, mod); ++#endif + /* Taints info */ + if (mod->taints) + seq_printf(m, " %s", module_flags(mod, buf)); +@@ -3097,8 +3100,12 @@ void print_modules(void) + printk(KERN_DEFAULT "Modules linked in:"); + /* Most callers should already have preempt disabled, but make sure */ + preempt_disable(); +- list_for_each_entry_rcu(mod, &modules, list) ++ list_for_each_entry_rcu(mod, &modules, list) { + printk(" %s%s", mod->name, module_flags(mod, buf)); ++#ifdef ARCH_OOPS_MODULE_EXTRA ++ ARCH_OOPS_MODULE_EXTRA(mod); ++#endif ++ } + preempt_enable(); + if (last_unloaded_module[0]) + printk(" [last unloaded: %s]", last_unloaded_module); +--- a/kernel/sched_clock.c ++++ b/kernel/sched_clock.c +@@ -38,8 +38,7 @@ + */ + unsigned long long __attribute__((weak)) sched_clock(void) + { +- return (unsigned long long)(jiffies - INITIAL_JIFFIES) +- * (NSEC_PER_SEC / HZ); ++ return (get_jiffies_64() - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ); + } + + static __read_mostly int sched_clock_running; +--- a/lib/Kconfig.debug ++++ b/lib/Kconfig.debug +@@ -690,7 +690,7 @@ config FRAME_POINTER + bool "Compile the kernel with frame pointers" + depends on DEBUG_KERNEL && \ + (CRIS || M68K || M68KNOMMU || FRV || UML || \ +- AVR32 || SUPERH || BLACKFIN || MN10300) || \ ++ AVR32 || SUPERH || BLACKFIN || MN10300 || UBICOM32) || \ + ARCH_WANT_FRAME_POINTERS + default y if (DEBUG_INFO && UML) || ARCH_WANT_FRAME_POINTERS + help +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -45,3 +45,5 @@ obj-$(CONFIG_MEMORY_FAILURE) += memory-f + obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o + obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o + obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o ++ ++CFLAGS_slab.o := $(PROFILING) -O2 +--- a/mm/slab.c ++++ b/mm/slab.c +@@ -4086,6 +4086,68 @@ out: + + #ifdef CONFIG_SLABINFO + ++ ++/* ++ * get info on all the memory allocated by slab for this named cache ++ */ ++int kmem_cache_block_info(char *name, struct kmem_cache_size_info *data, int max_data) ++{ ++ int res = 0; ++ int found = 0; ++ int node; ++ struct kmem_cache *cachep; ++ struct kmem_list3 *l3; ++ struct slab *slabp; ++ ++ /* Find the cache in the chain of caches. */ ++ mutex_lock(&cache_chain_mutex); ++ list_for_each_entry(cachep, &cache_chain, next) { ++ if (strcmp(cachep->name, name) == 0) { ++ found = 1; ++ break; ++ } ++ } ++ mutex_unlock(&cache_chain_mutex); ++ if (!found) { ++ return 0; ++ } ++ for_each_online_node(node) { ++ l3 = cachep->nodelists[node]; ++ if (!l3) ++ continue; ++ if (res >= max_data) ++ break; ++ check_irq_on(); ++ spin_lock_irq(&l3->list_lock); ++ ++ list_for_each_entry(slabp, &l3->slabs_full, list) { ++ if (res >= max_data) ++ break; ++ data[res].page = ((unsigned int)slabp->s_mem >> PAGE_SHIFT) & 0xffff; ++ data[res].order = cachep->gfporder; ++ res++; ++ } ++ list_for_each_entry(slabp, &l3->slabs_partial, list) { ++ if (res >= max_data) ++ break; ++ data[res].page = ((unsigned int)slabp->s_mem >> PAGE_SHIFT) & 0xffff; ++ data[res].order = cachep->gfporder; ++ res++; ++ } ++ list_for_each_entry(slabp, &l3->slabs_free, list) { ++ if (res >= max_data) ++ break; ++ data[res].page = ((unsigned int)slabp->s_mem >> PAGE_SHIFT) & 0xffff; ++ data[res].order = cachep->gfporder; ++ res++; ++ } ++ ++ spin_unlock_irq(&l3->list_lock); ++ } ++ ++ return res; ++} ++ + static void print_slabinfo_header(struct seq_file *m) + { + /* +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -783,6 +783,15 @@ void handle_moddevtable(struct module *m + + sym->st_value; + } + ++ /* ++ * somehow our gcc is not generating st_size correctly and set 0 for some symbols. ++ * and 0 size will break do_table since it adjust size to (size - id_size) ++ * this is to make sure st_size fall in range. ++ */ ++ if (sym->st_size == 0 || sym->st_size > info->sechdrs[sym->st_shndx].sh_size) { ++ sym->st_size = info->sechdrs[sym->st_shndx].sh_size; ++ } ++ + if (sym_is(symname, "__mod_pci_device_table")) + do_table(symval, sym->st_size, + sizeof(struct pci_device_id), "pci", +--- a/sound/Kconfig ++++ b/sound/Kconfig +@@ -110,6 +110,8 @@ source "sound/parisc/Kconfig" + + source "sound/soc/Kconfig" + ++source "sound/ubicom32/Kconfig" ++ + endif # SND + + menuconfig SOUND_PRIME +--- a/sound/Makefile ++++ b/sound/Makefile +@@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmw + obj-$(CONFIG_SOUND_PRIME) += oss/ + obj-$(CONFIG_DMASOUND) += oss/ + obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ +- sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ ++ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ ubicom32/ + obj-$(CONFIG_SND_AOA) += aoa/ + + # This one must be compilable even if sound is configured out diff --git a/target/linux/ubicom32/patches-2.6.32/110-vmlinux_lds_fix.patch b/target/linux/ubicom32/patches-2.6.32/110-vmlinux_lds_fix.patch new file mode 100644 index 000000000..1a1430887 --- /dev/null +++ b/target/linux/ubicom32/patches-2.6.32/110-vmlinux_lds_fix.patch @@ -0,0 +1,150 @@ +--- a/arch/ubicom32/kernel/vmlinux.lds.S ++++ b/arch/ubicom32/kernel/vmlinux.lds.S +@@ -25,7 +25,6 @@ + * arch/blackfin + * arch/parisc + */ +-#include + #include + #include + #include +@@ -201,94 +200,28 @@ SECTIONS { + *(__ex_table) + __stop___ex_table = .; + +- *(.rodata) *(.rodata.*) +- *(__vermagic) /* Kernel version magic */ +- *(__markers_strings) +- *(.rodata1) +- *(.rodata.str1.1) +- *(__tracepoints_strings) +- +- /* PCI quirks */ +- __start_pci_fixups_early = . ; +- *(.pci_fixup_early) +- __end_pci_fixups_early = . ; +- __start_pci_fixups_header = . ; +- *(.pci_fixup_header) +- __end_pci_fixups_header = . ; +- __start_pci_fixups_final = . ; +- *(.pci_fixup_final) +- __end_pci_fixups_final = . ; +- __start_pci_fixups_enable = . ; +- *(.pci_fixup_enable) +- __end_pci_fixups_enable = . ; +- __start_pci_fixups_resume = . ; +- *(.pci_fixup_resume) +- __end_pci_fixups_resume = . ; +- __start_pci_fixups_resume_early = . ; +- *(.pci_fixup_resume_early) +- __end_pci_fixups_resume_early = . ; +- __start_pci_fixups_suspend = . ; +- *(.pci_fixup_suspend) +- __end_pci_fixups_suspend = . ; +- +- __start_builtin_fw = . ; +- *(.builtin_fw) +- __end_builtin_fw = . ; +- +- +- /* Kernel symbol table: Normal symbols */ +- . = ALIGN(4); +- __start___ksymtab = .; +- *(__ksymtab) +- __stop___ksymtab = .; +- +- /* Kernel symbol table: GPL-only symbols */ +- __start___ksymtab_gpl = .; +- *(__ksymtab_gpl) +- __stop___ksymtab_gpl = .; +- +- /* Kernel symbol table: Normal unused symbols */ +- __start___ksymtab_unused = .; +- *(__ksymtab_unused) +- __stop___ksymtab_unused = .; +- +- /* Kernel symbol table: GPL-only unused symbols */ +- __start___ksymtab_unused_gpl = .; +- *(__ksymtab_unused_gpl) +- __stop___ksymtab_unused_gpl = .; +- +- /* Kernel symbol table: GPL-future symbols */ +- __start___ksymtab_gpl_future = .; +- *(__ksymtab_gpl_future) +- __stop___ksymtab_gpl_future = .; +- +- /* Kernel symbol table: Normal symbols */ +- __start___kcrctab = .; +- *(__kcrctab) +- __stop___kcrctab = .; +- +- /* Kernel symbol table: GPL-only symbols */ +- __start___kcrctab_gpl = .; +- *(__kcrctab_gpl) +- __stop___kcrctab_gpl = .; +- +- /* Kernel symbol table: GPL-future symbols */ +- __start___kcrctab_gpl_future = .; +- *(__kcrctab_gpl_future) +- __stop___kcrctab_gpl_future = .; ++ } > TEXT + +- /* Kernel symbol table: strings */ +- *(__ksymtab_strings) ++ RO_DATA(16) + +- /* Built-in module parameters */ +- . = ALIGN(4) ; +- __start___param = .; +- *(__param) +- __stop___param = .; ++ .rodata : {} > TEXT ++ .rodata1 : {} > TEXT ++ .pci_fixup : {} > TEXT ++ .builtin_fw : {} > TEXT ++ .rio_route : {} > TEXT ++ .tracedata : {} > TEXT ++ __ksymtab : {} > TEXT ++ __ksymtab_gpl : {} > TEXT ++ __ksymtab_gpl_future : {} > TEXT ++ __kcrctab_gpl : {} > TEXT ++ __kcrctab_unused : {} > TEXT ++ __kcrctab_unused_gpl : {} > TEXT ++ __kcrctab_gpl_future : {} > TEXT ++ __ksymtab_strings : {} > TEXT ++ __init_rodata : {} > TEXT ++ __param : {} > TEXT + +- . = ALIGN(4) ; +- _etext = . ; +- } > TEXT ++ _etext = .; + + .data DATA_ADDR : { + . = ALIGN(4); +@@ -349,12 +282,6 @@ SECTIONS { + PROVIDE (___eh_frame_end = .); + } > INIT + +- /DISCARD/ : { +- EXIT_TEXT +- EXIT_DATA +- *(.exitcall.exit) +- } +- + .bss : { + . = ALIGN(4); + _sbss = . ; +@@ -365,6 +292,12 @@ SECTIONS { + _end = . ; + } > BSS + ++ /DISCARD/ : { ++ EXIT_TEXT ++ EXIT_DATA ++ *(.exitcall.exit) ++ } ++ + NOTES > BSS + + } diff --git a/target/linux/ubicom32/patches-2.6.32/120-libgcc_func.patch b/target/linux/ubicom32/patches-2.6.32/120-libgcc_func.patch new file mode 100644 index 000000000..fee4ece00 --- /dev/null +++ b/target/linux/ubicom32/patches-2.6.32/120-libgcc_func.patch @@ -0,0 +1,419 @@ +--- a/arch/ubicom32/Makefile ++++ b/arch/ubicom32/Makefile +@@ -60,9 +60,6 @@ cflags-$(CONFIG_UBICOM32_V4) := -march= + ldflags-$(CONFIG_LINKER_RELAXATION) := --relax + LDFLAGS_vmlinux := $(ldflags-y) + +-GCCLIBDIR := $(dir $(shell $(CC) $(cflags-y) -print-libgcc-file-name)) +-GCC_LIBS := $(GCCLIBDIR)/libgcc.a +- + KBUILD_CFLAGS += $(cflags-y) -ffunction-sections + KBUILD_AFLAGS += $(cflags-y) + +@@ -84,7 +81,6 @@ core-y += arch/$(ARCH)/kernel/ \ + drivers-$(CONFIG_OPROFILE) += arch/ubicom32/oprofile/ + + libs-y += arch/$(ARCH)/lib/ +-libs-y += $(GCC_LIBS) + + archclean: + +--- a/arch/ubicom32/lib/Makefile ++++ b/arch/ubicom32/lib/Makefile +@@ -30,3 +30,4 @@ + # + + lib-y := checksum.o delay.o mem_ubicom32.o ++lib-y += ashldi3.o ashrdi3.o divmod.o lshrdi3.o muldi3.o +--- /dev/null ++++ b/arch/ubicom32/lib/ashldi3.c +@@ -0,0 +1,62 @@ ++/* ashrdi3.c extracted from gcc-2.95.2/libgcc2.c which is: */ ++/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++#define BITS_PER_UNIT 8 ++ ++typedef int SItype __attribute__ ((mode (SI))); ++typedef unsigned int USItype __attribute__ ((mode (SI))); ++typedef int DItype __attribute__ ((mode (DI))); ++typedef int word_type __attribute__ ((mode (__word__))); ++ ++struct DIstruct {SItype high, low;}; ++ ++typedef union ++{ ++ struct DIstruct s; ++ DItype ll; ++} DIunion; ++ ++DItype ++__ashldi3 (DItype u, word_type b) ++{ ++ DIunion w; ++ word_type bm; ++ DIunion uu; ++ ++ if (b == 0) ++ return u; ++ ++ uu.ll = u; ++ ++ bm = (sizeof (SItype) * BITS_PER_UNIT) - b; ++ if (bm <= 0) ++ { ++ w.s.low = 0; ++ w.s.high = (USItype)uu.s.low << -bm; ++ } ++ else ++ { ++ USItype carries = (USItype)uu.s.low >> bm; ++ w.s.low = (USItype)uu.s.low << b; ++ w.s.high = ((USItype)uu.s.high << b) | carries; ++ } ++ ++ return w.ll; ++} +--- /dev/null ++++ b/arch/ubicom32/lib/ashrdi3.c +@@ -0,0 +1,63 @@ ++/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ ++/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++#define BITS_PER_UNIT 8 ++ ++typedef int SItype __attribute__ ((mode (SI))); ++typedef unsigned int USItype __attribute__ ((mode (SI))); ++typedef int DItype __attribute__ ((mode (DI))); ++typedef int word_type __attribute__ ((mode (__word__))); ++ ++struct DIstruct {SItype high, low;}; ++ ++typedef union ++{ ++ struct DIstruct s; ++ DItype ll; ++} DIunion; ++ ++DItype ++__ashrdi3 (DItype u, word_type b) ++{ ++ DIunion w; ++ word_type bm; ++ DIunion uu; ++ ++ if (b == 0) ++ return u; ++ ++ uu.ll = u; ++ ++ bm = (sizeof (SItype) * BITS_PER_UNIT) - b; ++ if (bm <= 0) ++ { ++ /* w.s.high = 1..1 or 0..0 */ ++ w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1); ++ w.s.low = uu.s.high >> -bm; ++ } ++ else ++ { ++ USItype carries = (USItype)uu.s.high << bm; ++ w.s.high = uu.s.high >> b; ++ w.s.low = ((USItype)uu.s.low >> b) | carries; ++ } ++ ++ return w.ll; ++} +--- /dev/null ++++ b/arch/ubicom32/lib/divmod.c +@@ -0,0 +1,85 @@ ++unsigned long ++udivmodsi4(unsigned long num, unsigned long den, int modwanted) ++{ ++ unsigned long bit = 1; ++ unsigned long res = 0; ++ ++ while (den < num && bit && !(den & (1L<<31))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++long ++__udivsi3 (long a, long b) ++{ ++ return udivmodsi4 (a, b, 0); ++} ++ ++long ++__umodsi3 (long a, long b) ++{ ++ return udivmodsi4 (a, b, 1); ++} ++ ++long ++__divsi3 (long a, long b) ++{ ++ int neg = 0; ++ long res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodsi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++long ++__modsi3 (long a, long b) ++{ ++ int neg = 0; ++ long res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodsi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} +--- /dev/null ++++ b/arch/ubicom32/lib/lshrdi3.c +@@ -0,0 +1,62 @@ ++/* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ ++/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++#define BITS_PER_UNIT 8 ++ ++typedef int SItype __attribute__ ((mode (SI))); ++typedef unsigned int USItype __attribute__ ((mode (SI))); ++typedef int DItype __attribute__ ((mode (DI))); ++typedef int word_type __attribute__ ((mode (__word__))); ++ ++struct DIstruct {SItype high, low;}; ++ ++typedef union ++{ ++ struct DIstruct s; ++ DItype ll; ++} DIunion; ++ ++DItype ++__lshrdi3 (DItype u, word_type b) ++{ ++ DIunion w; ++ word_type bm; ++ DIunion uu; ++ ++ if (b == 0) ++ return u; ++ ++ uu.ll = u; ++ ++ bm = (sizeof (SItype) * BITS_PER_UNIT) - b; ++ if (bm <= 0) ++ { ++ w.s.high = 0; ++ w.s.low = (USItype)uu.s.high >> -bm; ++ } ++ else ++ { ++ USItype carries = (USItype)uu.s.high << bm; ++ w.s.high = (USItype)uu.s.high >> b; ++ w.s.low = ((USItype)uu.s.low >> b) | carries; ++ } ++ ++ return w.ll; ++} +--- /dev/null ++++ b/arch/ubicom32/lib/muldi3.c +@@ -0,0 +1,87 @@ ++/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and ++ gcc-2.7.2.3/longlong.h which is: */ ++/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++#define UWtype USItype ++#define UHWtype USItype ++#define W_TYPE_SIZE 32 ++#define __BITS4 (W_TYPE_SIZE / 4) ++#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) ++#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) ++#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) ++ ++#define umul_ppmm(w1, w0, u, v) \ ++ do { \ ++ UWtype __x0, __x1, __x2, __x3; \ ++ UHWtype __ul, __vl, __uh, __vh; \ ++ \ ++ __ul = __ll_lowpart (u); \ ++ __uh = __ll_highpart (u); \ ++ __vl = __ll_lowpart (v); \ ++ __vh = __ll_highpart (v); \ ++ \ ++ __x0 = (UWtype) __ul * __vl; \ ++ __x1 = (UWtype) __ul * __vh; \ ++ __x2 = (UWtype) __uh * __vl; \ ++ __x3 = (UWtype) __uh * __vh; \ ++ \ ++ __x1 += __ll_highpart (__x0);/* this can't give carry */ \ ++ __x1 += __x2; /* but this indeed can */ \ ++ if (__x1 < __x2) /* did we get it? */ \ ++ __x3 += __ll_B; /* yes, add it in the proper pos. */ \ ++ \ ++ (w1) = __x3 + __ll_highpart (__x1); \ ++ (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ ++ } while (0) ++ ++ ++#define __umulsidi3(u, v) \ ++ ({DIunion __w; \ ++ umul_ppmm (__w.s.high, __w.s.low, u, v); \ ++ __w.ll; }) ++ ++typedef int SItype __attribute__ ((mode (SI))); ++typedef unsigned int USItype __attribute__ ((mode (SI))); ++typedef int DItype __attribute__ ((mode (DI))); ++typedef int word_type __attribute__ ((mode (__word__))); ++ ++struct DIstruct {SItype high, low;}; ++ ++typedef union ++{ ++ struct DIstruct s; ++ DItype ll; ++} DIunion; ++ ++DItype ++__muldi3 (DItype u, DItype v) ++{ ++ DIunion w; ++ DIunion uu, vv; ++ ++ uu.ll = u, ++ vv.ll = v; ++ ++ w.ll = __umulsidi3 (uu.s.low, vv.s.low); ++ w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high ++ + (USItype) uu.s.high * (USItype) vv.s.low); ++ ++ return w.ll; ++} +--- a/arch/ubicom32/kernel/ubicom32_ksyms.c ++++ b/arch/ubicom32/kernel/ubicom32_ksyms.c +@@ -72,7 +72,6 @@ EXPORT_SYMBOL(memmove); + extern void __ashldi3(void); + extern void __ashrdi3(void); + extern void __divsi3(void); +-extern void __divdi3(void); + extern void __lshrdi3(void); + extern void __modsi3(void); + extern void __muldi3(void); +@@ -83,7 +82,6 @@ extern void __umodsi3(void); + EXPORT_SYMBOL(__ashldi3); + EXPORT_SYMBOL(__ashrdi3); + EXPORT_SYMBOL(__divsi3); +-EXPORT_SYMBOL(__divdi3); + EXPORT_SYMBOL(__lshrdi3); + EXPORT_SYMBOL(__modsi3); + EXPORT_SYMBOL(__muldi3); diff --git a/target/linux/ubicom32/patches-2.6.32/130-flash_driver_fix.patch b/target/linux/ubicom32/patches-2.6.32/130-flash_driver_fix.patch new file mode 100644 index 000000000..95fa50807 --- /dev/null +++ b/target/linux/ubicom32/patches-2.6.32/130-flash_driver_fix.patch @@ -0,0 +1,13 @@ +--- a/drivers/mtd/devices/ubi32-m25p80.c ++++ b/drivers/mtd/devices/ubi32-m25p80.c +@@ -630,8 +630,8 @@ static int ubicom32_flash_driver_erase(s + /* sanity checks */ + if (instr->addr + instr->len > flash->mtd.size) + return -EINVAL; +- if ((instr->addr % mtd->erasesize) != 0 +- || (instr->len % mtd->erasesize) != 0) { ++ if (((u32) instr->addr % mtd->erasesize) != 0 ++ || ((u32) instr->len % mtd->erasesize) != 0) { + return -EINVAL; + } + diff --git a/target/linux/ubicom32/patches-2.6.32/140-arch_cflags.patch b/target/linux/ubicom32/patches-2.6.32/140-arch_cflags.patch new file mode 100644 index 000000000..aa1396e41 --- /dev/null +++ b/target/linux/ubicom32/patches-2.6.32/140-arch_cflags.patch @@ -0,0 +1,13 @@ +--- a/arch/ubicom32/Makefile ++++ b/arch/ubicom32/Makefile +@@ -54,8 +54,8 @@ CFLAGS_MODULE += -mno-fastcall + # + # Some CFLAG additions based on specific CPU type. + # +-cflags-$(CONFIG_UBICOM32_V3) := -march=ubicom32v3 -DIP5000 +-cflags-$(CONFIG_UBICOM32_V4) := -march=ubicom32v4 -DIP7000 ++cflags-$(CONFIG_UBICOM32_V3) := -march=ubicom32v3 -mno-fdpic -DIP5000 ++cflags-$(CONFIG_UBICOM32_V4) := -march=ubicom32v4 -mno-fdpic -DIP7000 + + ldflags-$(CONFIG_LINKER_RELAXATION) := --relax + LDFLAGS_vmlinux := $(ldflags-y) diff --git a/target/linux/x86/Makefile b/target/linux/x86/Makefile index 41b348341..af12959cd 100644 --- a/target/linux/x86/Makefile +++ b/target/linux/x86/Makefile @@ -12,7 +12,7 @@ BOARDNAME:=x86 FEATURES:=squashfs jffs2 ext2 vdi vmdk pcmcia tgz SUBTARGETS=generic olpc xen_domu -LINUX_VERSION:=2.6.31.12 +LINUX_VERSION:=2.6.32.8 include $(INCLUDE_DIR)/target.mk diff --git a/target/linux/x86/config-default b/target/linux/x86/config-default index 884483995..6e26adc99 100644 --- a/target/linux/x86/config-default +++ b/target/linux/x86/config-default @@ -1,10 +1,12 @@ # CONFIG_3C515 is not set +CONFIG_4KSTACKS=y # CONFIG_60XX_WDT is not set # CONFIG_64BIT is not set # CONFIG_AC3200 is not set # CONFIG_ACPI_AC is not set # CONFIG_ACPI_ASUS is not set # CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_BUTTON is not set # CONFIG_ACPI_CONTAINER is not set # CONFIG_ACPI_CUSTOM_DSDT is not set @@ -13,92 +15,232 @@ # CONFIG_ACPI_FAN is not set # CONFIG_ACPI_PCI_SLOT is not set # CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_PROCESSOR=y +# CONFIG_ACPI_PROC_EVENT is not set # CONFIG_ACPI_PROCFS is not set # CONFIG_ACPI_PROCFS_POWER is not set -# CONFIG_ACPI_PROC_EVENT is not set # CONFIG_ACPI_SBS is not set +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_THERMAL=y # CONFIG_ACPI_TOSHIBA is not set # CONFIG_ACPI_WMI is not set +CONFIG_ACPI=y # CONFIG_ACQUIRE_WDT is not set # CONFIG_ADVANTECH_WDT is not set # CONFIG_ALIM1535_WDT is not set # CONFIG_APM is not set # CONFIG_APRICOT is not set +CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig" +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_DEFAULT_IDLE=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y # CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USES_PG_UNCACHED=y +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y # CONFIG_ASUS_LAPTOP is not set # CONFIG_AT1700 is not set +CONFIG_ATA_GENERIC=y +CONFIG_ATA_PIIX=y +CONFIG_ATA=y # CONFIG_AUDIT_ARCH is not set +CONFIG_BINFMT_MISC=y +CONFIG_BITREVERSE=y +CONFIG_BLK_DEV_SD=y # CONFIG_BLK_DEV_XD is not set +CONFIG_BOUNCE=y # CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CFG80211_DEFAULT_PS_VALUE=0 +CONFIG_CLOCKSOURCE_WATCHDOG=y # CONFIG_CMDLINE_BOOL is not set +CONFIG_COMPAT_VDSO=y +CONFIG_CONSOLE_TRANSLATIONS=y # CONFIG_CPU5_WDT is not set # CONFIG_CPU_FREQ_DEBUG is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set # CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_CENTAUR=y +CONFIG_CPU_SUP_CYRIX_32=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_TRANSMETA_32=y +CONFIG_CPU_SUP_UMC_32=y # CONFIG_CS5535_GPIO is not set # CONFIG_CS89x0 is not set # CONFIG_DCDBAS is not set +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DEFAULT_IO_DELAY_TYPE=0 # CONFIG_DELL_RBU is not set # CONFIG_DEPCA is not set -# CONFIG_DMAR is not set +CONFIG_DEVPORT=y # CONFIG_DMA_API_DEBUG is not set +# CONFIG_DMAR is not set # CONFIG_DMIID is not set +CONFIG_DMI=y +CONFIG_DNOTIFY=y +CONFIG_DOUBLEFAULT=y +CONFIG_DUMMY_CONSOLE=y # CONFIG_EARLY_PRINTK_DBGP is not set +CONFIG_EARLY_PRINTK=y # CONFIG_EDD is not set # CONFIG_EFI is not set # CONFIG_EISA is not set -# CONFIG_EL1 is not set # CONFIG_EL16 is not set +# CONFIG_EL1 is not set # CONFIG_EL2 is not set # CONFIG_EL3 is not set +CONFIG_ELF_CORE=y # CONFIG_ELPLUS is not set # CONFIG_EUROTECH_WDT is not set +CONFIG_EXT2_FS=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_FIX_EARLYCON_MEM=y # CONFIG_FRAME_POINTER is not set # CONFIG_FREEZER is not +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CMOS_UPDATE=y # CONFIG_GENERIC_CPU is not set +CONFIG_GENERIC_FIND_FIRST_BIT=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_ISA_DMA=y # CONFIG_GENERIC_PENDING_IRQ is not set # CONFIG_GENERIC_TIME_VSYSCALL is not set # CONFIG_HANGCHECK_TIMER is not set +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_AOUT=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_KMEMCHECK=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ATOMIC_IOMAP=y # CONFIG_HAVE_CPUMASK_OF_CPU_MAP is not set +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_KVM=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +CONFIG_HAVE_OPROFILE=y # CONFIG_HAVE_PERF_EVENTS is not set +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y # CONFIG_HIBERNATION is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set # CONFIG_HIGH_RES_TIMERS is not set # CONFIG_HOTPLUG_CPU is not set +CONFIG_HPET_EMULATE_RTC=y +CONFIG_HPET_MMAP=y +CONFIG_HPET_TIMER=y +CONFIG_HPET=y # CONFIG_HP_WATCHDOG is not set +CONFIG_HT_IRQ=y # CONFIG_HUGETLBFS is not set # CONFIG_HVC_DRIVER is not set # CONFIG_HVC_IRQ is not set # CONFIG_HVC_XEN is not set +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM_GEODE=y +CONFIG_HW_RANDOM_VIA=y +CONFIG_HW_RANDOM=y # CONFIG_I6300ESB_WDT is not set # CONFIG_I8K is not set # CONFIG_IB700_WDT is not set # CONFIG_IBMASR is not set # CONFIG_IMA is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT=y # CONFIG_INPUT_YEALINK is not set # CONFIG_INTEL_MENLOW is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +# CONFIG_IO_DELAY_UDELAY is not set # CONFIG_IOMMU_API is not set # CONFIG_IOMMU_HELPER is not set # CONFIG_IOMMU_STRESS is not set -# CONFIG_IO_DELAY_0XED is not set -# CONFIG_IO_DELAY_NONE is not set -# CONFIG_IO_DELAY_UDELAY is not set +CONFIG_ISA_DMA_API=y +CONFIG_ISAPNP=y +CONFIG_ISA=y # CONFIG_ISCSI_IBFT_FIND is not set # CONFIG_IT8712F_WDT is not set # CONFIG_IT87_WDT is not set # CONFIG_ITCO_WDT is not set +CONFIG_KALLSYMS=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +CONFIG_KEXEC=y +CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_NEWTON is not set # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_XTKBD is not set +CONFIG_KTIME_SCALAR=y # CONFIG_KVM_CLOCK is not set # CONFIG_KVM_GUEST is not set # CONFIG_LANCE is not set @@ -113,6 +255,7 @@ # CONFIG_M586TSC is not set # CONFIG_M686 is not set # CONFIG_MACHZ_WDT is not set +CONFIG_MATH_EMULATION=y # CONFIG_MATOM is not set # CONFIG_MCA is not set # CONFIG_MCORE2 is not set @@ -124,63 +267,109 @@ # CONFIG_MGEODEGX1 is not set # CONFIG_MGEODE_LX is not set # CONFIG_MICROCODE_AMD is not set +CONFIG_MICROCODE_INTEL=y +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_MICROCODE=y # CONFIG_MIXCOMWD is not set # CONFIG_MK6 is not set # CONFIG_MK7 is not set # CONFIG_MK8 is not set # CONFIG_MOUSE_BCM5974 is not set +CONFIG_MOUSE_PS2_ALPS=y # CONFIG_MOUSE_PS2_ELANTECH is not set +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y # CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_SERIAL is not set # CONFIG_MOUSE_VSXXXAA is not set # CONFIG_MPENTIUM4 is not set -# CONFIG_MPENTIUMII is not set # CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMII is not set # CONFIG_MPENTIUMM is not set # CONFIG_MPSC is not set +CONFIG_MTD_BLOCK2MTD=y # CONFIG_MTD_CFI is not set # CONFIG_MTD_COMPLEX_MAPPINGS is not set # CONFIG_MTD_TS5500 is not set # CONFIG_MTRR_SANITIZER is not set +CONFIG_MTRR=y # CONFIG_MVIAC3_2 is not set # CONFIG_MVIAC7 is not set # CONFIG_MWINCHIP3D is not set # CONFIG_MWINCHIPC6 is not set +CONFIG_NAMESPACES=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y # CONFIG_NET_NS is not set +CONFIG_NET_VENDOR_3COM=y # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_NET_VENDOR_SMC is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NOHIGHMEM=y # CONFIG_NR_CPUS is not set # CONFIG_NSC_GPIO is not set +CONFIG_NVRAM=y # CONFIG_OLPC is not set # CONFIG_OPTIMIZE_INLINING is not set -# CONFIG_PARAVIRT is not set +CONFIG_OUTPUT_FORMAT="elf32-i386" +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PAGE_OFFSET=0xC0000000 # CONFIG_PARAVIRT_CLOCK is not set # CONFIG_PARAVIRT_GUEST is not set +# CONFIG_PARAVIRT is not set # CONFIG_PARAVIRT_SPINLOCKS is not set +CONFIG_PATA_AMD=y +CONFIG_PATA_MPIIX=y +CONFIG_PATA_OLDPIIX=y +CONFIG_PATA_SC1200=y +CONFIG_PATA_VIA=y # CONFIG_PC8736x_GPIO is not set # CONFIG_PC87413_WDT is not set +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_DOMAINS=y # CONFIG_PCIEPORTBUS is not set +CONFIG_PCI_GOANY=y # CONFIG_PCI_GOBIOS is not set # CONFIG_PCI_GODIRECT is not set # CONFIG_PCI_GOMMCONFIG is not set # CONFIG_PCI_GOOLPC is not set +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_MSI=y +CONFIG_PCSPKR_PLATFORM=y # CONFIG_PCWATCHDOG is not set # CONFIG_PDA_POWER is not set # CONFIG_PERF_COUNTERS is not set # CONFIG_PERF_EVENTS is not set # CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_PHYSICAL_START=0x1000000 # CONFIG_PM_DEBUG is not set # CONFIG_PM_RUNTIME is not set # CONFIG_PM_SLEEP is not set # CONFIG_PM_SLEEP_SMP is not set +CONFIG_PM=y +CONFIG_PNPACPI=y # CONFIG_PNPBIOS is not set +CONFIG_PNP_DEBUG_MESSAGES=y +CONFIG_PNP=y # CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_POWER_SUPPLY=y # CONFIG_PROCESSOR_SELECT is not set +CONFIG_PROC_PAGE_MONITOR=y # CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_RCU_TRACE is not set +CONFIG_RD_BZIP2=y +CONFIG_RD_GZIP=y # CONFIG_RELOCATABLE is not set +CONFIG_RTC=y # CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y # CONFIG_SBC7240_WDT is not set # CONFIG_SBC8360_WDT is not set # CONFIG_SBC_EPX_C3_WATCHDOG is not set @@ -188,309 +377,89 @@ # CONFIG_SC520_WDT is not set # CONFIG_SCHED_HRTICK is not set # CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y # CONFIG_SCHED_SMT is not set # CONFIG_SCSI_LOWLEVEL is not set +CONFIG_SCSI=y # CONFIG_SCx200_GPIO is not set +CONFIG_SCx200HR_TIMER=y # CONFIG_SCx200_WDT is not set +CONFIG_SCx200=y # CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y # CONFIG_SERIO_CT82C710 is not set +CONFIG_SERIO_I8042=y +CONFIG_SERIO_LIBPS2=y # CONFIG_SERIO_PCIPS2 is not set # CONFIG_SERIO_RAW is not set +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO=y # CONFIG_SLAB is not set # CONFIG_SLUB_DEBUG_ON is not set +CONFIG_SLUB_DEBUG=y # CONFIG_SLUB_STATS is not set +CONFIG_SLUB=y # CONFIG_SMP is not set # CONFIG_SMSC37B787_WDT is not set # CONFIG_SMSC_SCH311X_WDT is not set # CONFIG_SPARSE_IRQ is not set +CONFIG_SPARSEMEM_STATIC=y # CONFIG_STOP_MACHINE is not set +CONFIG_STRICT_DEVMEM=y # CONFIG_SUSPEND is not set # CONFIG_SYS_HYPERVISOR is not set # CONFIG_TC1100_WMI is not set # CONFIG_TELCLOCK is not set +CONFIG_THERMAL=y # CONFIG_THINKPAD_ACPI is not set # CONFIG_TOPSTAR_LAPTOP is not set # CONFIG_TOSHIBA is not set # CONFIG_TREE_PREEMPT_RCU is not set +CONFIG_TREE_RCU=y # CONFIG_TYPHOON is not set -# CONFIG_USER_NS is not set +CONFIG_UID16=y +CONFIG_USB_SUPPORT=y # CONFIG_USE_GENERIC_SMP_HELPERS is not set +# CONFIG_USER_NS is not set +CONFIG_USER_STACKTRACE_SUPPORT=y # CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VGA_CONSOLE=y +CONFIG_VM86=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_VMI is not set # CONFIG_VORTEX is not set +CONFIG_VT_CONSOLE=y # CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_VT=y # CONFIG_W83697UG_WDT is not set # CONFIG_WAFER_WDT is not set # CONFIG_WDT is not set +CONFIG_X86_32_LAZY_GS=y # CONFIG_X86_32_SMP is not set +CONFIG_X86_32=y # CONFIG_X86_64 is not set # CONFIG_X86_ACPI_CPUFREQ is not set # CONFIG_X86_ANCIENT_MCE is not set # CONFIG_X86_BIGSMP is not set +CONFIG_X86_BSWAP=y # CONFIG_X86_CHECK_BIOS_CORRUPTION is not set # CONFIG_X86_CMOV is not set # CONFIG_X86_CMPXCHG64 is not set +CONFIG_X86_CMPXCHG=y +# CONFIG_X86_CPU_DEBUG is not set # CONFIG_X86_CPUFREQ_NFORCE2 is not set # CONFIG_X86_CPUID is not set -# CONFIG_X86_CPU_DEBUG is not set +CONFIG_X86_CPU=y # CONFIG_X86_DEBUGCTLMSR is not set # CONFIG_X86_DS is not set # CONFIG_X86_ELAN is not set -# CONFIG_X86_EXTENDED_PLATFORM is not set # CONFIG_X86_E_POWERSAVER is not set -# CONFIG_X86_GX_SUSPMOD is not set -# CONFIG_X86_HT is not set -# CONFIG_X86_LONGHAUL is not set -# CONFIG_X86_LONGRUN is not set -# CONFIG_X86_MCE_INJECT is not set -# CONFIG_X86_MRST is not set -# CONFIG_X86_MSR is not set -# CONFIG_X86_OLD_MCE is not set -# CONFIG_X86_P4_CLOCKMOD is not set -# CONFIG_X86_PAE is not set -# CONFIG_X86_POWERNOW_K6 is not set -# CONFIG_X86_POWERNOW_K7 is not set -# CONFIG_X86_POWERNOW_K8 is not set -# CONFIG_X86_RDC321X is not set -# CONFIG_X86_REBOOTFIXUPS is not set -# CONFIG_X86_SPEEDSTEP_CENTRINO is not set -# CONFIG_X86_SPEEDSTEP_ICH is not set -# CONFIG_X86_SPEEDSTEP_LIB is not set -# CONFIG_X86_SPEEDSTEP_SMI is not set -# CONFIG_X86_TRAMPOLINE is not set -# CONFIG_X86_TSC is not set -# CONFIG_X86_USE_PPRO_CHECKSUM is not set -# CONFIG_XEN is not set -# CONFIG_XENFS is not set -# CONFIG_XEN_BALLOON is not set -# CONFIG_XEN_BLKDEV_FRONTEND is not set -# CONFIG_XEN_DEBUG_FS is not set -# CONFIG_XEN_DEV_EVTCHN is not set -# CONFIG_XEN_MAX_DOMAIN_MEMORY is not set -# CONFIG_XEN_NETDEV_FRONTEND is not set -# CONFIG_XEN_SAVE_RESTORE is not set -# CONFIG_XEN_SCRUB_PAGES is not set -# CONFIG_XEN_SYS_HYPERVISOR is not set -# CONFIG_ZONE_DMA32 is not set -CONFIG_4KSTACKS=y -CONFIG_ACPI=y -CONFIG_ACPI_BLACKLIST_YEAR=0 -CONFIG_ACPI_PROCESSOR=y -CONFIG_ACPI_SYSFS_POWER=y -CONFIG_ACPI_THERMAL=y -CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig" -CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y -CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y -CONFIG_ARCH_HAS_CPU_RELAX=y -CONFIG_ARCH_HAS_DEFAULT_IDLE=y -CONFIG_ARCH_HIBERNATION_POSSIBLE=y -CONFIG_ARCH_MAY_HAVE_PC_FDC=y -CONFIG_ARCH_POPULATES_NODE_MAP=y -CONFIG_ARCH_SELECT_MEMORY_MODEL=y -CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y -CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y -CONFIG_ARCH_SUPPORTS_MSI=y -CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y -CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USES_PG_UNCACHED=y -CONFIG_ARCH_WANT_FRAME_POINTERS=y -CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y -CONFIG_ATA=y -CONFIG_ATA_GENERIC=y -CONFIG_ATA_PIIX=y -CONFIG_BINFMT_MISC=y -CONFIG_BITREVERSE=y -CONFIG_BLK_DEV_SD=y -CONFIG_BOUNCE=y -CONFIG_CFG80211_DEFAULT_PS_VALUE=0 -CONFIG_CLOCKSOURCE_WATCHDOG=y -CONFIG_COMPAT_VDSO=y -CONFIG_CONSOLE_TRANSLATIONS=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_STAT_DETAILS=y -CONFIG_CPU_FREQ_TABLE=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_GOV_LADDER=y -CONFIG_CPU_SUP_AMD=y -CONFIG_CPU_SUP_CENTAUR=y -CONFIG_CPU_SUP_CYRIX_32=y -CONFIG_CPU_SUP_INTEL=y -CONFIG_CPU_SUP_TRANSMETA_32=y -CONFIG_CPU_SUP_UMC_32=y -CONFIG_DEBUG_MEMORY_INIT=y -CONFIG_DECOMPRESS_BZIP2=y -CONFIG_DECOMPRESS_GZIP=y -CONFIG_DECOMPRESS_LZMA=y -CONFIG_DEFAULT_IO_DELAY_TYPE=0 -CONFIG_DEVPORT=y -CONFIG_DMI=y -CONFIG_DNOTIFY=y -CONFIG_DOUBLEFAULT=y -CONFIG_DUMMY_CONSOLE=y -CONFIG_EARLY_PRINTK=y -CONFIG_ELF_CORE=y -CONFIG_EXT2_FS=y -CONFIG_FIRMWARE_IN_KERNEL=y -CONFIG_FIRMWARE_MEMMAP=y -CONFIG_FIX_EARLYCON_MEM=y -CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -CONFIG_GENERIC_CMOS_UPDATE=y -CONFIG_GENERIC_FIND_FIRST_BIT=y -CONFIG_GENERIC_FIND_LAST_BIT=y -CONFIG_GENERIC_FIND_NEXT_BIT=y -CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y -CONFIG_GENERIC_IOMAP=y -CONFIG_GENERIC_ISA_DMA=y -CONFIG_HAS_DMA=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y -CONFIG_HAVE_AOUT=y -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_HAVE_ARCH_KMEMCHECK=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_ATOMIC_IOMAP=y -CONFIG_HAVE_DMA_API_DEBUG=y -CONFIG_HAVE_DMA_ATTRS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y -CONFIG_HAVE_GENERIC_DMA_COHERENT=y -CONFIG_HAVE_IDE=y -CONFIG_HAVE_IOREMAP_PROT=y -CONFIG_HAVE_KERNEL_BZIP2=y -CONFIG_HAVE_KERNEL_GZIP=y -CONFIG_HAVE_KERNEL_LZMA=y -CONFIG_HAVE_KERNEL_LZO=y -CONFIG_HAVE_KPROBES=y -CONFIG_HAVE_KRETPROBES=y -CONFIG_HAVE_KVM=y -CONFIG_HAVE_LATENCYTOP_SUPPORT=y -CONFIG_HAVE_MMIOTRACE_SUPPORT=y -CONFIG_HAVE_OPROFILE=y -CONFIG_HAVE_SETUP_PER_CPU_AREA=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y -CONFIG_HID=y -CONFIG_HID_SUPPORT=y -CONFIG_HPET=y -CONFIG_HPET_EMULATE_RTC=y -CONFIG_HPET_MMAP=y -CONFIG_HPET_TIMER=y -CONFIG_HT_IRQ=y -CONFIG_HW_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_GEODE=y -CONFIG_HW_RANDOM_VIA=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_INPUT=y -CONFIG_INPUT_KEYBOARD=y -CONFIG_INPUT_MOUSE=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -CONFIG_IO_DELAY_0X80=y -CONFIG_IO_DELAY_TYPE_0X80=0 -CONFIG_IO_DELAY_TYPE_0XED=1 -CONFIG_IO_DELAY_TYPE_NONE=3 -CONFIG_IO_DELAY_TYPE_UDELAY=2 -CONFIG_ISA=y -CONFIG_ISAPNP=y -CONFIG_ISA_DMA_API=y -CONFIG_KALLSYMS=y -CONFIG_KEXEC=y -CONFIG_KEYBOARD_ATKBD=y -CONFIG_KTIME_SCALAR=y -CONFIG_MATH_EMULATION=y -CONFIG_MICROCODE=y -CONFIG_MICROCODE_INTEL=y -CONFIG_MICROCODE_OLD_INTERFACE=y -CONFIG_MOUSE_PS2=y -CONFIG_MOUSE_PS2_ALPS=y -CONFIG_MOUSE_PS2_LIFEBOOK=y -CONFIG_MOUSE_PS2_LOGIPS2PP=y -CONFIG_MOUSE_PS2_SYNAPTICS=y -CONFIG_MOUSE_PS2_TRACKPOINT=y -CONFIG_MTD_BLOCK2MTD=y -CONFIG_MTRR=y -CONFIG_NAMESPACES=y -CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y -CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y -CONFIG_NETWORK_FILESYSTEMS=y -CONFIG_NET_VENDOR_3COM=y -CONFIG_NOHIGHMEM=y -CONFIG_NVRAM=y -CONFIG_OUTPUT_FORMAT="elf32-i386" -CONFIG_PAGEFLAGS_EXTENDED=y -CONFIG_PAGE_OFFSET=0xC0000000 -CONFIG_PATA_AMD=y -CONFIG_PATA_MPIIX=y -CONFIG_PATA_OLDPIIX=y -CONFIG_PATA_SC1200=y -CONFIG_PATA_VIA=y -CONFIG_PCI_BIOS=y -CONFIG_PCI_DIRECT=y -CONFIG_PCI_DOMAINS=y -CONFIG_PCI_GOANY=y -CONFIG_PCI_MMCONFIG=y -CONFIG_PCI_MSI=y -CONFIG_PCSPKR_PLATFORM=y -CONFIG_PHYSICAL_ALIGN=0x100000 -CONFIG_PHYSICAL_START=0x1000000 -CONFIG_PM=y -CONFIG_PNP=y -CONFIG_PNPACPI=y -CONFIG_PNP_DEBUG_MESSAGES=y -CONFIG_POWER_SUPPLY=y -CONFIG_PROC_PAGE_MONITOR=y -CONFIG_RCU_FANOUT=32 -CONFIG_RD_BZIP2=y -CONFIG_RD_GZIP=y -CONFIG_RTC=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_SCHED_OMIT_FRAME_POINTER=y -CONFIG_SCSI=y -CONFIG_SCx200=y -CONFIG_SCx200HR_TIMER=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_PNP=y -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_LIBPS2=y -CONFIG_SERIO_SERPORT=y -CONFIG_SLUB=y -CONFIG_SLUB_DEBUG=y -CONFIG_SPARSEMEM_STATIC=y -CONFIG_STRICT_DEVMEM=y -CONFIG_THERMAL=y -CONFIG_TREE_RCU=y -CONFIG_UID16=y -CONFIG_USB_SUPPORT=y -CONFIG_USER_STACKTRACE_SUPPORT=y -CONFIG_VGA_CONSOLE=y -CONFIG_VM86=y -CONFIG_VM_EVENT_COUNTERS=y -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_X86=y -CONFIG_X86_32=y -CONFIG_X86_32_LAZY_GS=y -CONFIG_X86_BSWAP=y -CONFIG_X86_CMPXCHG=y -CONFIG_X86_CPU=y +# CONFIG_X86_EXTENDED_PLATFORM is not set CONFIG_X86_F00F_BUG=y CONFIG_X86_GENERIC=y +# CONFIG_X86_GX_SUSPMOD is not set +# CONFIG_X86_HT is not set CONFIG_X86_INTEL_USERCOPY=y CONFIG_X86_INTERNODE_CACHE_BYTES=64 CONFIG_X86_INVLPG=y @@ -498,23 +467,56 @@ CONFIG_X86_IO_APIC=y CONFIG_X86_L1_CACHE_BYTES=64 CONFIG_X86_L1_CACHE_SHIFT=6 CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_MCE=y +# CONFIG_X86_LONGHAUL is not set +# CONFIG_X86_LONGRUN is not set CONFIG_X86_MCE_AMD=y +# CONFIG_X86_MCE_INJECT is not set CONFIG_X86_MCE_INTEL=y CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE=y CONFIG_X86_MINIMUM_CPU_FAMILY=4 CONFIG_X86_MPPARSE=y +# CONFIG_X86_MRST is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_OLD_MCE is not set +# CONFIG_X86_P4_CLOCKMOD is not set +# CONFIG_X86_PAE is not set CONFIG_X86_PAT=y CONFIG_X86_PLATFORM_DEVICES=y CONFIG_X86_PM_TIMER=y CONFIG_X86_POPAD_OK=y +# CONFIG_X86_POWERNOW_K6 is not set +# CONFIG_X86_POWERNOW_K7 is not set +# CONFIG_X86_POWERNOW_K8 is not set CONFIG_X86_PPRO_FENCE=y +# CONFIG_X86_RDC321X is not set +# CONFIG_X86_REBOOTFIXUPS is not set CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y CONFIG_X86_RESERVE_LOW_64K=y +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_SPEEDSTEP_ICH is not set +# CONFIG_X86_SPEEDSTEP_LIB is not set +# CONFIG_X86_SPEEDSTEP_SMI is not set CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y CONFIG_X86_THERMAL_VECTOR=y +# CONFIG_X86_TRAMPOLINE is not set +# CONFIG_X86_TSC is not set CONFIG_X86_UP_APIC=y CONFIG_X86_UP_IOAPIC=y +# CONFIG_X86_USE_PPRO_CHECKSUM is not set CONFIG_X86_VERBOSE_BOOTUP=y CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_XADD=y +CONFIG_X86=y +# CONFIG_XEN_BALLOON is not set +# CONFIG_XEN_BLKDEV_FRONTEND is not set +# CONFIG_XEN_DEBUG_FS is not set +# CONFIG_XEN_DEV_EVTCHN is not set +# CONFIG_XENFS is not set +# CONFIG_XEN is not set +# CONFIG_XEN_MAX_DOMAIN_MEMORY is not set +# CONFIG_XEN_NETDEV_FRONTEND is not set +# CONFIG_XEN_SAVE_RESTORE is not set +# CONFIG_XEN_SCRUB_PAGES is not set +# CONFIG_XEN_SYS_HYPERVISOR is not set +# CONFIG_ZONE_DMA32 is not set diff --git a/target/linux/x86/image/Config.in b/target/linux/x86/image/Config.in index d52ae0c07..9d17f37b6 100644 --- a/target/linux/x86/image/Config.in +++ b/target/linux/x86/image/Config.in @@ -2,14 +2,21 @@ config X86_GRUB_IMAGES bool "Build GRUB images (Linux x86 or x86_64 host only)" depends TARGET_x86 && !TARGET_x86_olpc depends TARGET_ROOTFS_EXT2FS || TARGET_ROOTFS_JFFS2 || TARGET_ROOTFS_SQUASHFS || TARGET_ROOTFS_ISO - select PACKAGE_grub + select PACKAGE_grub default y config X86_GRUB_IMAGES_PAD - bool "Pad GRUB images to filesystem size (for JFFS2)" - depends X86_GRUB_IMAGES + bool "Pad GRUB images to filesystem size (for JFFS2)" + depends X86_GRUB_IMAGES config X86_GRUB_CONSOLE + bool + depends X86_GRUB_IMAGES + prompt "Use Console Terminal (in addition to Serial)" + default n if TARGET_x86_generic_Soekris48xx || TARGET_x86_generic_Soekris45xx + default y if ! (TARGET_x86_generic_Soekris48xx || TARGET_x86_generic_Soekris45xx) + +config X86_GRUB_SERIAL string prompt "Serial port device" depends X86_GRUB_IMAGES @@ -19,7 +26,8 @@ config X86_GRUB_CONSOLE config X86_GRUB_BAUDRATE int "Serial port baud rate" depends X86_GRUB_IMAGES - default 38400 + default 19200 if TARGET_x86_generic_Soekris48xx || TARGET_x86_generic_Soekris45xx + default 38400 if ! (TARGET_x86_generic_Soekris48xx || TARGET_x86_generic_Soekris45xx) config X86_GRUB_KERNELPART int "Kernel partition size (in MB)" diff --git a/target/linux/x86/image/Makefile b/target/linux/x86/image/Makefile index 13712cf0e..b2167e748 100644 --- a/target/linux/x86/image/Makefile +++ b/target/linux/x86/image/Makefile @@ -20,7 +20,25 @@ ROOTPART=$(strip $(subst ",, $(CONFIG_OLPC_BOOTSCRIPT_ROOTPART))) endif #"))")) # fix vim's broken syntax highlighting -CONSOLE=$(strip $(subst ",, $(CONFIG_X86_GRUB_CONSOLE))) +GRUB_TERMINALS = +GRUB_SERIAL_CONFIG = +GRUB_TERMINAL_CONFIG = +GRUB_CONSOLE_CMDLINE = + +ifeq ($(CONFIG_X86_GRUB_CONSOLE),y) +GRUB_CONSOLE_CMDLINE += console=tty0 +GRUB_TERMINALS += console +endif + +ifneq ($(CONFIG_X86_GRUB_SERIAL),) +GRUB_CONSOLE_CMDLINE += console=$(strip $(subst ",, $(CONFIG_X86_GRUB_SERIAL))),$(CONFIG_X86_GRUB_BAUDRATE)n8 +GRUB_SERIAL_CONFIG = serial --unit=0 --speed=$(CONFIG_X86_GRUB_BAUDRATE) --word=8 --parity=no --stop=1 +GRUB_TERMINALS += serial +endif + +ifneq ($(GRUB_TERMINALS),) +GRUB_TERMINAL_CONFIG = terminal --timeout=2 $(GRUB_TERMINALS) +endif ifeq ($(CONFIG_X86_GRUB_IMAGES),y) @@ -49,9 +67,9 @@ ifneq ($(HOST_OS),Darwin) $(KDIR)/root.grub/boot/grub/ $(CP) $(KDIR)/bzImage $(KDIR)/root.grub/boot/vmlinuz sed \ - -e 's#@CMDLINE@#$(strip $(call Image/cmdline/$(1))) $(BOOTOPTS)#g' \ - -e 's#@CONSOLE@#$(CONSOLE)#g' \ - -e 's#@BAUDRATE@#$(CONFIG_X86_GRUB_BAUDRATE)#g' \ + -e 's#@SERIAL_CONFIG@#$(strip $(GRUB_SERIAL_CONFIG))#g' \ + -e 's#@TERMINAL_CONFIG@#$(strip $(GRUB_TERMINAL_CONFIG))#g' \ + -e 's#@CMDLINE@#$(strip $(call Image/cmdline/$(1)) $(BOOTOPTS) $(GRUB_CONSOLE_CMDLINE))#g' \ ./menu.lst > $(KDIR)/root.grub/boot/grub/menu.lst PADDING="$(CONFIG_X86_GRUB_IMAGES_PAD)" PATH="$(TARGET_PATH)" ./gen_image_x86.sh $(BIN_DIR)/openwrt-$(BOARD)-$(1).image $(CONFIG_X86_GRUB_KERNELPART) $(KDIR)/root.grub $(CONFIG_TARGET_ROOTFS_FSPART) $(KDIR)/root.$(1) $(call Image/Build/grub/$(1)) @@ -141,8 +159,9 @@ define Image/Build/iso $(STAGING_DIR_HOST)/usr/lib/grub/i386-openwrt/stage2_eltorito \ $(KDIR)/root.grub/boot/grub/stage2_eltorito sed \ - -e 's#@CMDLINE@#$(strip $(call Image/cmdline/$(1))) $(BOOTOPTS)#g' \ - -e 's#@BAUDRATE@#$(CONFIG_X86_GRUB_BAUDRATE)#g' \ + -e 's#@SERIAL_CONFIG@#$(strip $(GRUB_SERIAL_CONFIG))#g' \ + -e 's#@TERMINAL_CONFIG@#$(strip $(GRUB_TERMINAL_CONFIG))#g' \ + -e 's#@CMDLINE@#$(strip $(call Image/cmdline/$(1)) $(BOOTOPTS) $(GRUB_CONSOLE_CMDLINE))#g' \ -e 's#(hd0,0)#(cd)#g' \ ./menu.lst > $(KDIR)/root.grub/boot/grub/menu.lst $(CP) $(KDIR)/bzImage $(KDIR)/root.grub/boot/vmlinuz diff --git a/target/linux/x86/image/menu.lst b/target/linux/x86/image/menu.lst index e09177c96..5f99f2156 100644 --- a/target/linux/x86/image/menu.lst +++ b/target/linux/x86/image/menu.lst @@ -1,15 +1,15 @@ -serial --unit=0 --speed=@BAUDRATE@ --word=8 --parity=no --stop=1 -terminal --timeout=2 console serial +@SERIAL_CONFIG@ +@TERMINAL_CONFIG@ default 0 timeout 5 title OpenWrt root (hd0,0) -kernel /boot/vmlinuz @CMDLINE@ noinitrd console=tty0 console=@CONSOLE@,@BAUDRATE@n8 reboot=bios +kernel /boot/vmlinuz @CMDLINE@ noinitrd reboot=bios boot title OpenWrt (failsafe) root (hd0,0) -kernel /boot/vmlinuz failsafe=true @CMDLINE@ noinitrd console=tty0 console=@CONSOLE@,@BAUDRATE@n8 reboot=bios +kernel /boot/vmlinuz failsafe=true @CMDLINE@ noinitrd reboot=bios boot diff --git a/target/linux/x86/patches-2.6.32/300-block2mtd_init.patch b/target/linux/x86/patches-2.6.32/300-block2mtd_init.patch deleted file mode 100644 index 1ac85a332..000000000 --- a/target/linux/x86/patches-2.6.32/300-block2mtd_init.patch +++ /dev/null @@ -1,213 +0,0 @@ ---- a/drivers/mtd/devices/block2mtd.c -+++ b/drivers/mtd/devices/block2mtd.c -@@ -18,10 +18,18 @@ - #include - #include - #include -+#include -+#include - - #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) - #define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args) - -+struct retry { -+ struct list_head list; -+ const char *val; -+}; -+ -+static LIST_HEAD(retry_list); - - /* Info for the block device */ - struct block2mtd_dev { -@@ -33,10 +41,34 @@ - char devname[0]; - }; - -+static int block2mtd_setup2(const char *val); - - /* Static info about the MTD, used in cleanup_module */ - static LIST_HEAD(blkmtd_device_list); - -+static int add_retry(const char *val) { -+ struct retry *r = kmalloc(sizeof(struct retry), GFP_KERNEL); -+ -+ INIT_LIST_HEAD(&r->list); -+ r->val = val; -+ list_add(&r->list, &retry_list); -+ -+ return 0; -+} -+ -+static int __init process_retries(void) { -+ struct list_head *p, *tmp; -+ -+ list_for_each_safe(p, tmp, &retry_list) { -+ struct retry *r = list_entry(p, struct retry, list); -+ block2mtd_setup2(r->val); -+ msleep(100); -+ list_del(p); -+ kfree(r); -+ } -+ return 0; -+} -+rootfs_initcall(process_retries); - - static struct page *page_read(struct address_space *mapping, int index) - { -@@ -511,7 +543,9 @@ - if (token[2] && (strlen(token[2]) + 1 > 80)) - parse_err("mtd device name too long"); - -- add_device(name, erase_size, token[2]); -+ if (add_device(name, erase_size, token[2]) == NULL) { -+ add_retry(val); -+ } - - return 0; - } ---- a/include/asm-generic/vmlinux.lds.h -+++ b/include/asm-generic/vmlinux.lds.h -@@ -614,17 +614,24 @@ - *(.initcall4s.init) \ - *(.initcall5.init) \ - *(.initcall5s.init) \ -- *(.initcallrootfs.init) \ - *(.initcall6.init) \ - *(.initcall6s.init) \ - *(.initcall7.init) \ - *(.initcall7s.init) - -+#define INITCALLS_ROOT \ -+ *(.initcallrootfs.init) -+ - #define INIT_CALLS \ - VMLINUX_SYMBOL(__initcall_start) = .; \ - INITCALLS \ - VMLINUX_SYMBOL(__initcall_end) = .; - -+#define INIT_CALLS_ROOT \ -+ VMLINUX_SYMBOL(__root_initcall_start) = .; \ -+ INITCALLS_ROOT \ -+ VMLINUX_SYMBOL(__root_initcall_end) = .; -+ - #define CON_INITCALL \ - VMLINUX_SYMBOL(__con_initcall_start) = .; \ - *(.con_initcall.init) \ -@@ -766,6 +773,7 @@ - INIT_DATA \ - INIT_SETUP(initsetup_align) \ - INIT_CALLS \ -+ INIT_CALLS_ROOT \ - CON_INITCALL \ - SECURITY_INITCALL \ - INIT_RAM_FS \ ---- a/init/do_mounts.c -+++ b/init/do_mounts.c -@@ -176,16 +176,8 @@ - return 1; - } - --static unsigned int __initdata root_delay; --static int __init root_delay_setup(char *str) --{ -- root_delay = simple_strtoul(str, NULL, 0); -- return 1; --} -- - __setup("rootflags=", root_data_setup); - __setup("rootfstype=", fs_names_setup); --__setup("rootdelay=", root_delay_setup); - - static void __init get_fs_names(char *page) - { -@@ -366,23 +358,6 @@ - { - int is_floppy; - -- if (root_delay) { -- printk(KERN_INFO "Waiting %dsec before mounting root device...\n", -- root_delay); -- ssleep(root_delay); -- } -- -- /* -- * wait for the known devices to complete their probing -- * -- * Note: this is a potential source of long boot delays. -- * For example, it is not atypical to wait 5 seconds here -- * for the touchpad of a laptop to initialize. -- */ -- wait_for_device_probe(); -- -- md_run_setup(); -- - if (saved_root_name[0]) { - root_device_name = saved_root_name; - if (!strncmp(root_device_name, "mtd", 3) || ---- a/init/main.c -+++ b/init/main.c -@@ -80,6 +80,7 @@ - #ifdef CONFIG_X86_LOCAL_APIC - #include - #endif -+#include "do_mounts.h" - - static int kernel_init(void *); - -@@ -752,12 +753,13 @@ - - - extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[]; -+extern initcall_t __root_initcall_start[], __root_initcall_end[]; - --static void __init do_initcalls(void) -+static void __init do_initcalls(initcall_t *start, initcall_t *end) - { - initcall_t *call; - -- for (call = __early_initcall_end; call < __initcall_end; call++) -+ for (call = start; call < end; call++) - do_one_initcall(*call); - - /* Make sure there is no pending stuff from the initcall sequence */ -@@ -780,7 +782,7 @@ - driver_init(); - init_irq_proc(); - do_ctors(); -- do_initcalls(); -+ do_initcalls(__early_initcall_end, __initcall_end); - } - - static void __init do_pre_smp_initcalls(void) -@@ -841,6 +843,13 @@ - panic("No init found. Try passing init= option to kernel."); - } - -+static unsigned int __initdata root_delay; -+static int __init root_delay_setup(char *str) -+{ -+ root_delay = simple_strtoul(str, NULL, 0); -+ return 1; -+} -+__setup("rootdelay=", root_delay_setup); - static int __init kernel_init(void * unused) - { - lock_kernel(); -@@ -885,7 +894,16 @@ - - if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) { - ramdisk_execute_command = NULL; -- prepare_namespace(); -+ if (root_delay) { -+ printk(KERN_INFO "Waiting %desc before mounting root device...\n", -+ root_delay); -+ ssleep(root_delay); -+ } -+ while (driver_probe_done() != 0) -+ msleep(100); -+ do_initcalls(__root_initcall_start, __root_initcall_end); -+ md_run_setup(); -+ prepare_namespace(); - } - - /* diff --git a/target/linux/x86/xen_domu/config-default b/target/linux/x86/xen_domu/config-default index 0e8a382f0..c5f8ce1d2 100644 --- a/target/linux/x86/xen_domu/config-default +++ b/target/linux/x86/xen_domu/config-default @@ -1,17 +1,15 @@ -# CONFIG_KERNEL_LZMA is not set CONFIG_ARCH_PHYS_ADDR_T_64BIT=y CONFIG_FREEZER=y CONFIG_GENERIC_PENDING_IRQ=y CONFIG_HVC_DRIVER=y CONFIG_HVC_IRQ=y CONFIG_HVC_XEN=y -CONFIG_KERNEL_GZIP=y CONFIG_LOCK_KERNEL=y CONFIG_MPENTIUM4=y CONFIG_NR_CPUS=4 -CONFIG_PARAVIRT=y CONFIG_PARAVIRT_CLOCK=y CONFIG_PARAVIRT_GUEST=y +CONFIG_PARAVIRT=y CONFIG_PHYS_ADDR_T_64BIT=y CONFIG_SCHED_MC=y CONFIG_SMP=y @@ -30,10 +28,10 @@ CONFIG_X86_PAE=y CONFIG_X86_TRAMPOLINE=y CONFIG_X86_TSC=y CONFIG_X86_USE_PPRO_CHECKSUM=y -CONFIG_XEN=y CONFIG_XEN_BALLOON=y CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_MAX_DOMAIN_MEMORY=8 CONFIG_XEN_SAVE_RESTORE=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_SYS_HYPERVISOR=y +CONFIG_XEN=y diff --git a/target/linux/xburst/Makefile b/target/linux/xburst/Makefile index 7fdb93ce1..37ab41ba7 100644 --- a/target/linux/xburst/Makefile +++ b/target/linux/xburst/Makefile @@ -11,7 +11,7 @@ BOARD:=xburst BOARDNAME:=XBurst JZ47x0 FEATURES:=jffs2 tgz ubifs audio -LINUX_VERSION:=2.6.32.7 +LINUX_VERSION:=2.6.32.8 DEVICE_TYPE=other diff --git a/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/board-qi_lb60.h b/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/board-qi_lb60.h index e5de9da7a..cfbf0733b 100644 --- a/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/board-qi_lb60.h +++ b/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/board-qi_lb60.h @@ -20,11 +20,6 @@ #define __ASM_JZ4740_QI_LB60_H__ #include -/* - * Frequencies of on-board oscillators - */ -#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ -#define JZ_EXTAL_RTC 32768 /* RTC extal freq: 32.768 KHz */ /* * GPIO diff --git a/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/clock.h b/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/clock.h index c75c07b37..1f8e53b25 100644 --- a/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/clock.h +++ b/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/clock.h @@ -23,7 +23,6 @@ enum jz4740_wait_mode JZ4740_WAIT_MODE_SLEEP, }; -int jz_init_clocks(unsigned long ext_rate); void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode); void jz4740_clock_udc_enable_auto_suspend(void); diff --git a/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/jz4740.h b/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/jz4740.h index 7f9293a9a..9885db243 100644 --- a/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/jz4740.h +++ b/target/linux/xburst/files-2.6.32/arch/mips/include/asm/mach-jz4740/jz4740.h @@ -26,9 +26,6 @@ #include #endif -/* Add other platform definition here ... */ - - /*------------------------------------------------------------------ * Follows are related to platform definitions */ diff --git a/target/linux/xburst/files-2.6.32/arch/mips/jz4740/board-n526.c b/target/linux/xburst/files-2.6.32/arch/mips/jz4740/board-n526.c index fa4627807..6e65417eb 100644 --- a/target/linux/xburst/files-2.6.32/arch/mips/jz4740/board-n526.c +++ b/target/linux/xburst/files-2.6.32/arch/mips/jz4740/board-n526.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include